Element Ui是如何高效率实现实现组件之间的通信的?
事件监听和事件触发
vm.$emit( eventName, […args] )
vm.$on( event, callback )
事件监听
// form-item.vue
addValidateEvents() {
const rules = this.getRules();
if (rules.length || this.required !== undefined) {
this.$on('el.form.blur', this.onFieldBlur);
this.$on('el.form.change', this.onFieldChange);
}
}
事件触发
因为可能在不同的多个组件里面都有监听这个事件,ElementUi使用了以下两种方式:
- dispatch函数是不停的向上去遍历父节点并且通过$emit去触发事件,到达根节点之后停止。
- broadcast函数是不停的去遍历子节点并且通过$emit去触发事件,直到所有的子节点遍历完成之后停止。
// emitter.js
function _broadcast(componentName, eventName, params) {
this.$children.forEach(function (child) {
var name = child.$options.componentName;
if (name === componentName) {
child.$emit.apply(child, [eventName].concat(params));
} else {
_broadcast.apply(child, [componentName, eventName].concat([params]));
}
});
}
exports.default = {
methods: {
dispatch: function dispatch(componentName, eventName, params) {
var parent = this.$parent || this.$root;
var name = parent.$options.componentName;
while (parent && (!name || name !== componentName)) {
parent = parent.$parent;
if (parent) {
name = parent.$options.componentName;
}
}
if (parent) {
parent.$emit.apply(parent, [eventName].concat(params));
}
},
broadcast: function broadcast(componentName, eventName, params) {
_broadcast.call(this, componentName, eventName, params);
}
}
};
// input.vue
handleBlur(event) {
this.focused = false;
this.$emit('blur', event);
if (this.validateEvent) {
this.dispatch('ElFormItem', 'el.form.blur', [this.value]);
}
}
mixins
为了能够方便快速的复用dispatch和broadcast方法,elementui采用了mixins混入的方式将emitter.js注入到个个需要的组件。
export default {
name: 'ElInput',
componentName: 'ElInput',
mixins: [emitter, Migrating],
... ...