element message-box源码

Posted wsk1576025821

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了element message-box源码相关的知识,希望对你有一定的参考价值。

本文参考https://www.cnblogs.com/fangnianqin/p/10769949.html

src/main.vue

<template>
  <transition name="msgbox-fade">
  <!--包裹弹框的div-->
    <div
      class="el-message-box__wrapper"
      tabindex="-1"
      v-show="visible"
      @click.self="handleWrapperClick"
      role="dialog"
      aria-modal="true"
      :aria-label="title || ‘dialog‘">
      <!--中间的弹框-->
      <div class="el-message-box" :class="[customClass, center && ‘el-message-box--center‘]">
       <!--弹窗头部,包含:标题和关闭按钮;title必须设置,如果不设置不显示头部信息-->
        <div class="el-message-box__header" v-if="title !== null">
          <!--头部标题-->
          <div class="el-message-box__title">
          <!--center为true时,为居中布局,可设置图标,图标和标题居中显示-->
            <div
              :class="[‘el-message-box__status‘, icon]"
              v-if="icon && center">
            </div>
            <span> title </span>
          </div>
          <button
            type="button"
            class="el-message-box__headerbtn"
            aria-label="Close"
            v-if="showClose"
            @click="handleAction(distinguishCancelAndClose ? ‘close‘ : ‘cancel‘)"
            @keydown.enter="handleAction(distinguishCancelAndClose ? ‘close‘ : ‘cancel‘)">
            <i class="el-message-box__close el-icon-close"></i>
          </button>
        </div>
        <!--弹框内容部分-->
        <div class="el-message-box__content">
        <!--消息类型的图标-->
          <div
            :class="[‘el-message-box__status‘, icon]"
            v-if="icon && !center && message !== ‘‘">
          </div>
          <!--弹框的主要内容-->
          <div class="el-message-box__message" v-if="message !== ‘‘">
            <slot>
              <!--dangerouslyUsehtmlString是否将 message 属性作为 HTML 片段处理,如果该字段不存在时,直接显示message-->
              <p v-if="!dangerouslyUseHTMLString"> message </p>
              <!--如果存在将message作为HTML处理-->
              <p v-else v-html="message"></p>
            </slot>
          </div>
          <!--输入框部分,根据设置的showInput显示-->
          <div class="el-message-box__input" v-show="showInput">
            <el-input
              v-model="inputValue"
              :type="inputType"
              @keydown.enter.native="handleInputEnter"
              :placeholder="inputPlaceholder"
              ref="input"></el-input>
              <!--检验错误的提示信息-->
            <div class="el-message-box__errormsg" :style=" visibility: !!editorErrorMessage ? ‘visible‘ : ‘hidden‘ "> editorErrorMessage </div>
          </div>
        </div>
        <!--弹框底部,包含:确认、取消按钮-->
        <div class="el-message-box__btns">
          <el-button
            :loading="cancelButtonLoading"
            :class="[ cancelButtonClasses ]"
            v-if="showCancelButton"
            :round="roundButton"
            size="small"
            @click.native="handleAction(‘cancel‘)"
            @keydown.enter="handleAction(‘cancel‘)">
             cancelButtonText || t(‘el.messagebox.cancel‘) 
          </el-button>
          <el-button
            :loading="confirmButtonLoading"
            ref="confirm"
            :class="[ confirmButtonClasses ]"
            v-show="showConfirmButton"
            :round="roundButton"
            size="small"
            @click.native="handleAction(‘confirm‘)"
            @keydown.enter="handleAction(‘confirm‘)">
             confirmButtonText || t(‘el.messagebox.confirm‘) 
          </el-button>
        </div>
      </div>
    </div>
  </transition>
</template>

<script type="text/babel">
  import Popup from element-ui/src/utils/popup;
  import Locale from element-ui/src/mixins/locale;
  import ElInput from element-ui/packages/input;
  import ElButton from element-ui/packages/button;
  import  addClass, removeClass  from element-ui/src/utils/dom;
  import  t  from element-ui/src/locale;
  import Dialog from element-ui/src/utils/aria-dialog;

  let messageBox;
  //定义的图标类型
  let typeMap = 
    success: success,
    info: info,
    warning: warning,
    error: error
  ;

  export default 
    mixins: [Popup, Locale],

    props: 
      modal: 
        default: true
      ,
      // 是否在 MessageBox 出现时将 body 滚动锁定
      lockScroll: 
        default: true
      ,
      // MessageBox 是否显示右上角关闭按钮
      showClose: 
        type: Boolean,
        default: true
      ,
      // 是否可通过点击遮罩关闭 MessageBox    boolean    —    true(以 alert 方式调用时为 false)
      closeOnClickModal: 
        default: true
      ,
      // 是否可通过按下 ESC 键关闭 MessageBox    boolean    —    true(以 alert 方式调用时为 false)
      closeOnPressEscape: 
        default: true
      ,
      // 是否在 hashchange 时关闭 MessageBox    boolean    —    true
      closeOnHashChange: 
        default: true
      ,
      // 是否居中布局
      center: 
        default: false,
        type: Boolean
      ,
      // 是否使用圆角按钮
      roundButton: 
        default: false,
        type: Boolean
      
    ,

    components: 
      ElInput,
      ElButton
    ,

    computed: 
      icon() 
        const  type, iconClass  = this;
        //如果用户设置了自定义图标的类名,就显示自定义图标;如果没有就显示设置的type图标,否则就不显示图标
        return iconClass || (type && typeMap[type] ? `el-icon-$ typeMap[type] ` : ‘‘);
      ,
      //添加确定按钮的自定义类名
      confirmButtonClasses() 
        return `el-button--primary $ this.confirmButtonClass `;
      ,
      //添加取消按钮的自定义类名
      cancelButtonClasses() 
        return `$ this.cancelButtonClass `;
      
    ,

    methods: 
      // 关闭
      getSafeClose() 
        const currentId = this.uid;
        return () => 
          this.$nextTick(() => 
            if (currentId === this.uid) this.doClose();
          );
        ;
      ,
      // 执行关闭事件
      doClose() 
        if (!this.visible) return;
        this.visible = false;
        this._closing = true;

        this.onClose && this.onClose();
        messageBox.closeDialog(); // 解绑
        // 如果是弹出框出来锁定body
        if (this.lockScroll) 
          setTimeout(this.restoreBodyStyle, 200);
        
        this.opened = false;
        this.doAfterClose();
        setTimeout(() => 
          if (this.action) this.callback(this.action, this);
        );
      ,
      //点击弹框时,根据closeOnClickModal来是否可通过点击遮罩关闭 MessageBox
      handleWrapperClick() 
        // 如果closeOnClickModal设置为true
        if (this.closeOnClickModal) 
          //判断是否将取消(点击取消按钮)与关闭(点击关闭按钮或遮罩层、按下 ESC 键)进行区分
          //如果区分则this.handleAction(‘close‘);否则this.handleAction(‘cancel‘);
          this.handleAction(this.distinguishCancelAndClose ? close : cancel);
        
      ,
      // 输入框键盘enter事件
      handleInputEnter() 
        if (this.inputType !== textarea) 
          // 确认
          return this.handleAction(confirm);
        
      ,

      handleAction(action) 
        // 如果当前是this.$prompt并且点击了确认按钮并且没有验证通过
        if (this.$type === prompt && action === confirm && !this.validate()) 
          return;
        
        this.action = action;
        //判断beforeClose是否是函数,也就是用户是否定义了beforeClose函数
        if (typeof this.beforeClose === function) 
          this.close = this.getSafeClose();
          /** 
            MessageBox 关闭前的回调,会暂停实例的关闭    function(action, instance, done),action 的值为‘confirm‘,
            ‘cancel‘或‘close‘;instance 为 MessageBox 实例,可以通过它访问实例上的属性和方法;done 用于关闭 MessageBox 实例
          */
          this.beforeClose(action, this, this.close);
         else 
          //如果用户没有定义beforeClose,就调doClose直接关闭弹框
          this.doClose();
        
      ,
      //该方法主要是用于用户在调用$prompt方法打开消息提示时,校验input输入框的值
      validate() 
        //$prompt方法即可打开消息提示,它模拟了系统的 prompt
        if (this.$type === prompt) 
          //获取用户自己定义的匹配模式
          const inputPattern = this.inputPattern;
          //如果用户自己定义了匹配模式,并且用户输入校验不通过
          if (inputPattern && !inputPattern.test(this.inputValue || ‘‘)) 
            //显示用户自己定义的校验不通过时的提示信息;当用户未定义校验不通过的提示信息时,t(‘el.messagebox.error‘)输出提示:输入的数据不合法!
            this.editorErrorMessage = this.inputErrorMessage || t(el.messagebox.error);
            //这里主要是在校验不通过时,给input加上的类名中加上invalid,变成class="el-input__inner invalid"
            //通过.el-message-box__input input.invalidborder-color: #f56c6c;改变input的border为红色
            addClass(this.getInputElement(), invalid);
            return false;
          
          //输入框的校验函数;可以返回布尔值或字符串,若返回一个字符串, 则返回结果会被赋值给 inputErrorMessage
          const inputValidator = this.inputValidator;
          //如果校验函数存在
          if (typeof inputValidator === function) 
            const validateResult = inputValidator(this.inputValue);
            //校验不通过,显示校验不通过的红色提示信息
            if (validateResult === false) 
              this.editorErrorMessage = this.inputErrorMessage || t(el.messagebox.error);
              addClass(this.getInputElement(), invalid);
              return false;
            
            //若返回一个字符串, 则返回结果会被赋值给 inputErrorMessage
            if (typeof validateResult === string) 
              this.editorErrorMessage = validateResult;
              addClass(this.getInputElement(), invalid);
              return false;
            
          
        
        //如果校验通过,则不显示错误提示,并删除类名invalid
        this.editorErrorMessage = ‘‘;
        removeClass(this.getInputElement(), invalid);
        return true;
      ,
      // 获取第一个聚焦元素
      getFirstFocus() 
        const btn = this.$el.querySelector(.el-message-box__btns .el-button);
        const title = this.$el.querySelector(.el-message-box__btns .el-message-box__title);
        return btn || title;
      ,
      // 获取输入框元素
      getInputElement() 
        const inputRefs = this.$refs.input.$refs;
        return inputRefs.input || inputRefs.textarea;
      
    ,

    watch: 
      // 监听输入值得变化
      inputValue: 
        immediate: true,//立即触发
        handler(val)  //自定义函数
          this.$nextTick(_ => 
            if (this.$type === prompt && val !== null) 
              this.validate();
            
          );
        
      ,
      // 是否显示messagebox框
      visible(val) 
        if (val) 
          this.uid++;
          // 如果是this.$alert或者this.$confirm
          if (this.$type === alert || this.$type === confirm) 
            this.$nextTick(() => 
              // 确认按钮聚焦
              this.$refs.confirm.$el.focus();
            );
          
          // document.activeElement -> 当前获取焦点的元素
          this.focusAfterClosed = document.activeElement;
          messageBox = new Dialog(this.$el, this.focusAfterClosed, this.getFirstFocus());
        

        // prompt
        if (this.$type !== prompt) return;
        if (val) 
          setTimeout(() => 
            if (this.$refs.input && this.$refs.input.$el) 
              this.getInputElement().focus();
            
          , 500);
         else 
          this.editorErrorMessage = ‘‘;
          removeClass(this.getInputElement(), invalid);
        
      
    ,

    mounted() 
      this.$nextTick(() => 
        if (this.closeOnHashChange) 
          //如果需要,则在元素挂载之后,给window添加hashchange事件
          window.addEventListener(hashchange, this.close);
        
      );
    ,

    beforeDestroy() 
      // 组件销毁时移除hashchange事件
      if (this.closeOnHashChange) 
        window.removeEventListener(hashchange, this.close);
      
      setTimeout(() => 
        messageBox.closeDialog(); //解绑
      );
    ,

    data() 
      return 
        uid: 1,
        title: undefined, //MessageBox 标题
        message: ‘‘, //MessageBox 消息正文内容
        type: ‘‘, //消息类型,用于显示图标
        iconClass: ‘‘, //自定义图标的类名,会覆盖 type
        customClass: ‘‘, //MessageBox 的自定义类名
        showInput: false, //是否显示输入框
        inputValue: null, //输入框的初始文本
        inputPlaceholder: ‘‘, //输入框的占位符
        inputType: text, //输入框的类型
        inputPattern: null, //输入框的校验表达式
        inputValidator: null,//输入框的校验函数。可以返回布尔值或字符串,若返回一个字符串, 则返回结果会被赋值给 inputErrorMessage
        inputErrorMessage: ‘‘, //校验未通过时的提示文本
        showConfirmButton: true, //是否显示确定按钮
        showCancelButton: false, //是否显示取消按钮
        action: ‘‘, //操作确认还是取消
        confirmButtonText: ‘‘,//确定按钮的文本内容
        cancelButtonText: ‘‘,//取消按钮的文本内容
        confirmButtonLoading: false, //确认按钮的loading状态
        cancelButtonLoading: false,//取消按钮的loading状态
        confirmButtonClass: ‘‘,//确认按钮的类名
        confirmButtonDisabled: false,//确认按钮是否禁用
        cancelButtonClass: ‘‘,//取消按钮的类名
        editorErrorMessage: null,//错误信息提示
        callback: null,//回调函数
        dangerouslyUseHTMLString: false,// 是否将 message 属性作为 HTML 片段处理
        focusAfterClosed: null,
        isOnComposition: false,
        distinguishCancelAndClose: false//是否将取消(点击取消按钮)与关闭(点击关闭按钮或遮罩层、按下 ESC 键)进行区分
      ;
    
  ;
</script>

src/main.js

const defaults = 
  title: null,//MessageBox 标题
  message: ‘‘,//MessageBox 消息正文内容
  type: ‘‘,//消息类型,用于显示图标
  iconClass: ‘‘,//自定义图标的类名,会覆盖 type
  showInput: false, //是否显示输入框
  showClose: true,//MessageBox 是否显示右上角关闭按钮
  modalFade: true,
  lockScroll: true,//是否在 MessageBox 出现时将 body 滚动锁定
  closeOnClickModal: true,//是否可通过点击遮罩关闭 MessageBox
  closeOnPressEscape: true,//是否可通过按下 ESC 键关闭 MessageBox
  closeOnHashChange: true,//是否在 hashchange 时关闭 MessageBox
  inputValue: null,//输入框的初始文本
  inputPlaceholder: ‘‘,//输入框的占位符
  inputType: ‘text‘,//输入框的类型
  inputPattern: null, //输入框的校验表达式
  inputValidator: null,//输入框的校验函数。可以返回布尔值或字符串,若返回一个字符串, 则返回结果会被赋值给 inputErrorMessage
  inputErrorMessage: ‘‘,//校验未通过时的提示文本
  showConfirmButton: true,//是否显示确定按钮
  showCancelButton: false,//是否显示取消按钮
  confirmButtonPosition: ‘right‘,
  confirmButtonHighlight: false,
  cancelButtonHighlight: false,
  confirmButtonText: ‘‘, //确定按钮的文本内容
  cancelButtonText: ‘‘,//取消按钮的文本内容
  confirmButtonClass: ‘‘,//确定按钮的自定义类名
  cancelButtonClass: ‘‘,//取消按钮的自定义类名
  customClass: ‘‘,//MessageBox 的自定义类名 
  beforeClose: null,//MessageBox 关闭前的回调,会暂停实例的关闭
  dangerouslyUseHTMLString: false,//是否将 message 属性作为 HTML 片段处理
  center: false,//是否居中布局
  roundButton: false,//是否使用圆角按钮
  distinguishCancelAndClose: false//是否将取消(点击取消按钮)与关闭(点击关闭按钮或遮罩层、按下 ESC 键)进行区分
;

import Vue from ‘vue‘;
import msgboxVue from ‘./main.vue‘;
import merge from ‘element-ui/src/utils/merge‘;
import  isVNode  from ‘element-ui/src/utils/vdom‘;
//创建MessageBox的构造器,包含msgboxVue组件选项的对象作为Vue.extend的参数,返回一个VueComponent类,VueComponent类是Vue类的子类
//Vue.extend是一个类构造器,用来创建一个子类vue并返回构造函数,而Vue.component它的任务是将给定的构造函数与字符串ID相关联,以便Vue.js可以在模板中接收它。
const MessageBoxConstructor = Vue.extend(msgboxVue);

let currentMsg, instance;
let msgQueue = [];

const defaultCallback = action => 
  if (currentMsg) 
    let callback = currentMsg.callback;
    if (typeof callback === ‘function‘) 
      if (instance.showInput) 
        callback(instance.inputValue, action);
       else 
        callback(action);
      
    
    if (currentMsg.resolve) 
      // 点击确定或者去下关闭按钮时,在此处调对应的方法进行处理
      if (action === ‘confirm‘) 
        //执行确认后的回调方法
        if (instance.showInput) 
          currentMsg.resolve( value: instance.inputValue, action );
         else 
          currentMsg.resolve(action);
        
       else if (currentMsg.reject && (action === ‘cancel‘ || action === ‘close‘)) 
        //执行取消和关闭后的回调方法
        currentMsg.reject(action);
      
    
  
;

const initInstance = () => 
  //instance为messageBox的实例
  instance = new MessageBoxConstructor(
    el: document.createElement(‘div‘)
  );

  instance.callback = defaultCallback;
;

const showNextMsg = () => 
  if (!instance) 
    // 调用initInstance初始化实例,返回messageBox的实例对象
    initInstance();
  
  instance.action = ‘‘;

  if (!instance.visible || instance.closeTimer) 
    if (msgQueue.length > 0) 
      currentMsg = msgQueue.shift();
      //将用户设置的属性和方法挂载到messageBox的实例对象instance上去
      let options = currentMsg.options;
      for (let prop in options) 
        if (options.hasOwnProperty(prop)) 
          instance[prop] = options[prop];
        
      
      //当用户未设置callback时,将defaultCallback赋值给instance.callback
      if (options.callback === undefined) 
        instance.callback = defaultCallback;
      

      let oldCb = instance.callback;
      instance.callback = (action, instance) => 
        oldCb(action, instance);
        showNextMsg();
      ;
      if (isVNode(instance.message)) 
        instance.$slots.default = [instance.message];
        instance.message = null;
       else 
        delete instance.$slots.default;
      
      // 默认设置为true
      [‘modal‘, ‘showClose‘, ‘closeOnClickModal‘, ‘closeOnPressEscape‘, ‘closeOnHashChange‘].forEach(prop => 
        if (instance[prop] === undefined) 
          instance[prop] = true;
        
      );
      document.body.appendChild(instance.$el);

      Vue.nextTick(() => 
        instance.visible = true;
      );
    
  
;

const MessageBox = function (options, callback) 
  if (Vue.prototype.$isServer) return;
  if (typeof options === ‘string‘ || isVNode(options)) 
    options = 
      message: options
    ;
    // 第二个参数设置为title
    if (typeof arguments[1] === ‘string‘) 
      options.title = arguments[1];
    
   else if (options.callback && !callback) 
    callback = options.callback;
  

  if (typeof Promise !== ‘undefined‘) 
    return new Promise((resolve, reject) =>  // eslint-disable-line
      // options合并默认的所有参数和用户设置的参数
      msgQueue.push(
        options: merge(, defaults, MessageBox.defaults, options),
        callback: callback,
        resolve: resolve,
        reject: reject
      );

      showNextMsg();
    );
   else 
    msgQueue.push(
      options: merge(, defaults, MessageBox.defaults, options),
      callback: callback
    );

    showNextMsg();
  
;

MessageBox.setDefaults = defaults => 
  MessageBox.defaults = defaults;
;
//this.$alert方法
MessageBox.alert = (message, title, options) => 
  //如果title的类型为object时,用户可能没传title,则将title的值赋值给options
  if (typeof title === ‘object‘) 
    options = title;
    title = ‘‘;
   else if (title === undefined) 
    title = ‘‘;
  
  //合并用户传的参数,并调用MessageBox方法
  return MessageBox(merge(
    title: title,
    message: message,
    $type: ‘alert‘,
    closeOnPressEscape: false,
    closeOnClickModal: false
  , options));
;
//this.$confirm方法,分析同MessageBox.alert方法
MessageBox.confirm = (message, title, options) => 
  if (typeof title === ‘object‘) 
    options = title;
    title = ‘‘;
   else if (title === undefined) 
    title = ‘‘;
  
  return MessageBox(merge(
    title: title,
    message: message,
    $type: ‘confirm‘,
    showCancelButton: true
  , options));
;
//this.$prompt方法,分析同MessageBox.alert方法
MessageBox.prompt = (message, title, options) => 
  if (typeof title === ‘object‘) 
    options = title;
    title = ‘‘;
   else if (title === undefined) 
    title = ‘‘;
  
  return MessageBox(merge(
    title: title,
    message: message,
    showCancelButton: true,
    showInput: true,
    $type: ‘prompt‘
  , options));
;
// 关闭
MessageBox.close = () => 
  instance.doClose();
  instance.visible = false;
  msgQueue = [];
  currentMsg = null;
;

export default MessageBox;
export  MessageBox ;

 

以上是关于element message-box源码的主要内容,如果未能解决你的问题,请参考以下文章

Selenium Xpath元素无法定位 NoSuchElementException: Message: no such element: Unable to locate element(代码片段

js代码片段: utils/lcoalStorage/cookie

TP5报如下的错误 Indirect modification of overloaded element of thinkpaginatorCollection has no effect(代码片段

maven web项目的web.xml报错The markup in the document following the root element must be well-formed.(代码片段

css样式表中的 font:messagebox 一句是啥意思啊?

VSCode自定义代码片段5——HTML元素结构