優點:適合開發層級不會很複雜的獨立元件,無需藉助vuex
缺點:依賴元件樹的結構,比如需要知道A和B誰是父,誰是子,然後父中broadcast,子中dispatch。
先列一個簡單的case:
<!--child.vue-->
export default {
methods: {
handleEmitEvent () {
this.$emit('test', 'Hello Vue.js')
}
}
}
複製程式碼
<!--parent.vue-->
<template>
<child-component @test="handleEvent">
</template>
<script>
export default {
methods: {
handleEvent (text) {
console.log(text) // Hello Vue.js
}
}
}
</script>
複製程式碼
子元件觸發($emit),父元件監聽($on)。
So, 既然是子元件自己觸發的,那它自己也可以監聽到, 即元件自己監聽自己的emit。
<template>
<div>
<button @click="handleEmitEvent">觸發自定義事件</button>
</div>
</template>
<script>
export default {
methods: {
handleEmitEvent () {
this.$emit('test', 'Hello Vue.js')
}
},
created () {
this.$on('test', (text) => {
console.log(text) // Hello Vue.js
});
}
}
</script>
複製程式碼
乍一看多次一舉, handleEmitEvent可以直接寫邏輯,沒必要emit,on這樣繞了一圈
如果handleEmitEvent不是通過該元件自身呼叫的呢?
設想這樣的場景,A是父元件,B是子元件,中間可能跨多級。 A向B通訊:
<!--A.vue-->
<template>
<input @focus="handleFocus">觸發事件 />
</template>
<script>
import Emitter from '../mixins/emitter.js'; // 先忽略混入的內容
export default {
name: 'componentA',
mixins: [ Emitter ],
methods: {
handleFocus () {
this.broadcast('componentB', 'sendMessage', '我被點了'); // 後面會放實現邏輯
}
}
}
</script>
複製程式碼
<!--B.vue-->
<script>
export default {
name: 'componentB',
created () {
this.$on('sendMessage', this.showMessage)
},
methods: {
showMessage (text) {
console.log(text); // 我被點了
}
}
}
</script>
複製程式碼
事件觸發點是A元件中的input被focus,但是為什麼B元件中可以監聽到呢?
看完下面Emitter的實現就明白了。
function broadcast(componentName, eventName, params) {
this.$children.forEach(child => {
const name = child.$options.name;
if (name === componentName) {
child.$emit.apply(child, [eventName].concat(params));
} else {
broadcast.apply(child, [componentName, eventName].concat([params]));
}
});
}
export default {
methods: {
dispatch(componentName, eventName, params) {
let parent = this.$parent || this.$root;
let name = parent.$options.name;
while (parent && (!name || name !== componentName)) {
parent = parent.$parent;
if (parent) {
name = parent.$options.name;
}
}
if (parent) {
parent.$emit.apply(parent, [eventName].concat(params));
}
},
broadcast(componentName, eventName, params) {
broadcast.call(this, componentName, eventName, params);
}
}
};
複製程式碼
通過mixins可以將dispatch和broadcast方法merge到A元件中,
broadcast就是向下遞迴遍歷通過name尋找指定的元件(componentB), dispatch同理。
實際上最終還是在找到的B中呼叫$emit觸發自定義事件,所以B也就可以監聽到該事件的觸發,
但是事件的源頭卻是從A觸發,也就實現了A和B的通訊。
參考 Vue.js元件精講 juejin.im/book/5bc844…
注:emitter.js 參考 github.com/iview/iview…