elementUI——mixins

说明:本文基于[email protected],源码详见element。

src/mixins/emitter.js中有两个方法:dispatchbroadcast,这两个方法在多处用到:
例如,在packages/select/src/select.vue中,value的监控方法中用到dispatchbroadcast

watch: {
  value(val, oldVal) {
    if (!valueEquals(val, oldVal)) {
       this.dispatch('ElFormItem', 'el.form.change', val);
    }
  },
  visible(val) {
    if (!val) {
       this.broadcast('ElSelectDropdown', 'destroyPopper');
    }
  }
}

一、dispatch(子组件发送消息给上层组件)

dispatch(componentName, eventName, params) {
      // 当前父组件
      var parent = this.$parent || this.$root;
      // 当前父组件的组件名
      var name = parent.$options.componentName;

      // 通过$parent,一直向上找,直到组件名等于componentName
      while (parent && (!name || name !== componentName)) {
        parent = parent.$parent;

        if (parent) {
          name = parent.$options.componentName;
        }
      }
      if (parent) {
        // 如果找到目标组件,那么调用目标组件的$emit方法
        parent.$emit.apply(parent, [eventName].concat(params));
      }
    }

还是以packages/select/src/select.vue为例:


  
    
    
  

el-select组件中调用dispatch方法(this.dispatch('ElFormItem', 'el.form.change', val)),通过while循环,找到上层名为ElFormItem的组件,并在上层组件实例中$emit el.form.change事件,最后,在packages/form/src/form-item.vue中,通过$on方法捕获该事件:

addValidateEvents() {
        ......
        if (rules.length || this.required !== undefined) {
          ......
          this.$on('el.form.change', this.onFieldChange);
        }
}

二、broadcast(上层组件通知下层组件)

function broadcast(componentName, eventName, params) {
  // 遍历所有子组件
  this.$children.forEach(child => {
    var name = child.$options.componentName;
    // 找到组件名为componentName的子组件,并调用该子组件的$emit方法;
    // 否则,继续递归
    if (name === componentName) {
      child.$emit.apply(child, [eventName].concat(params));
    } else {
      broadcast.apply(child, [componentName, eventName].concat([params]));
    }
  });
}

还是以packages/select/src/select.vue为例:


 
 

el-select组件中调用broadcast方法:

handleQueryChange(val) {
        ......
        this.broadcast('ElOption', 'queryChange', val);
        ......
} 

上面代码,会向所有el-option子组件广播queryChange事件并携带数据,在el-option组件的created方法中会通过$on方法响应:

created() {
      ......
      this.$on('queryChange', this.queryChange);
      ......
}

三、src/mixins/migrating.js:对发生改动的props或eventName发出警告

export default {
  mounted() {
    if (process.env.NODE_ENV === 'production') return;
    if (!this.$vnode) return;
    const { props = {}, events = {} } = this.getMigratingConfig();
    const { data, componentOptions } = this.$vnode;
    const definedProps = data.attrs || {};
    const definedEvents = componentOptions.listeners || {};

    for (let propName in definedProps) {
      propName = kebabCase(propName); // compatible with camel case
      if (props[propName]) {
        console.warn(`[Element Migrating][${this.$options.name}][Attribute]: ${props[propName]}`);
      }
    }

    for (let eventName in definedEvents) {
      eventName = kebabCase(eventName); // compatible with camel case
      if (events[eventName]) {
        console.warn(`[Element Migrating][${this.$options.name}][Event]: ${events[eventName]}`);
      }
    }
  },
  methods: {
    getMigratingConfig() {
      return {
        props: {},
        events: {}
      };
    }
  }
};

其中,kebabCase方法的作用是将类似abCd这种格式转换成ab-cd,也就是驼峰形式转成短横线连接的形式。
上面的mounted和getMigratingConfig都会混入各个组件之中,以packages/autocomplete/src/autocomplete.vue为例:
在该文件中,实现了getMigratingConfig方法:

getMigratingConfig() {
        return {
          props: {
            'custom-item': 'custom-item is removed, use scoped slot instead.',
            'props': 'props is removed, use value-key instead.'
          }
        };
},

在非生产环境中,当加载了el-autocomplete组件后,就会爆出两条警告:
custom-item is removed, use scoped slot instead.
props is removed, use value-key instead.

推荐

ElementUI的结构与源码研究
elementUI——locale,国际化方案
elementUI——directives:mousewheel & repeat-click
elementU——transitions
elementUI——主题

你可能感兴趣的:(elementUI——mixins)