淺談Vue2.0父子組件間事件派發(fā)機制
從vue1.x過來的都知道,在vue2.0中,父子組件間事件通信的$dispatch和$broadcase被移除了。官方考慮是基于組件樹結(jié)構(gòu)的事件流方式實在是讓人難以理解,并且在組件結(jié)構(gòu)擴展的過程中會變得越來越脆落。特別是在組件層級比較深的情況下。通過廣播和事件分發(fā)的機制,就顯得比較混亂了。
官方在廢除的同時,也為我們提供了替換方案,包括實例化一個空的vue實例,使用$emit反應(yīng)子組件上的狀態(tài)變化
1.使用$emit觸發(fā)事件
helloWorld.vue作為父組件,dialogConfigVisible變量控制子組件彈框顯示或隱藏。
configBox.vue作為子組件,假設(shè)為封裝的公告彈窗。
在父組件中 helloWorld.vue 中
< template/>
<config-box :visible="dialogConfigVisible" @listenToConfig="changeConfigVisible" > </config-box>
script
data(){
return {
dialogConfigVisible:true
}
}
methods: {
changeConfigVisible(flag) {
this.dialogConfigVisible = flag;
}
}
然后,在子組件 configBox.vue 中,主要在任意事件回調(diào)中,使用 $emit來觸發(fā)自定義的 listenToConfig事件,后面還可以加上參數(shù)傳給父組件。比如,在子組件彈窗上點擊×關(guān)閉時,通知父組件 helloWorld.vue我要關(guān)閉了,主要方便父組件改變相應(yīng)狀態(tài)變量,并傳入false到自定義的事件中。
script
methods:{
dialogClose() {
this.show = false;
this.$emit("listenToConfig", false)
}
}
在子組件中,主動觸發(fā)listenToConfig事件,并傳入?yún)?shù) false, 告訴父組件 helloWorld.vue對話框要關(guān)閉了。這里就可以避免父組件中的狀態(tài)未變化,再次刷新頁面的時候?qū)υ捒驎詣映霈F(xiàn)。
2.實例化一個空的vue實例bus
這里實例化一個bus 空vue實例,主要為了統(tǒng)一管理子組件和父組件相互通信,通過bus 作為媒介,首先新建一個bus.js 文件,在里面新建一個對象,父組件為table.vue, 子組件為tableColumn.vue
// bus.js
import Vue from "vue";
export var bus = new Vue({
data:{
scrollY:false
},
methods:{
updateScrollY(flag){
this.scrollY = flag;
}
}
})
然后分別引入:
// table.vue
<script>
import {bus} from "./bus"
export default {
created(){
bus.$on('getData',(argsData)=>{
// 這里獲取子組件傳來的參數(shù)
console.log(argsData);
})
}
}
</script>
// tableColumn.vue
<script>
import {bus} from "./bus"
export default{
methods(){
handleClick(){
bus.$emit('getData',{data:"from tableColumn!"})
}
}
}
</script>
上面的父子組件中,父組件中利用bus注冊監(jiān)聽事件getData,子組件中一旦有狀態(tài)變化,就觸發(fā)bus上對應(yīng)的事件。
這種利用空實例的方式,相當于創(chuàng)建了一個事件中心,所以這種通信同樣適用于非父子組件間的通信,
3.多級父子組件通信
有時,可能想要實現(xiàn)通信的兩個組件不是直接的父子組件,而是祖父和孫子,或者是跨越了更多層級的父子組件
不可能由子組件一級一級的向上傳遞參數(shù),來達到通信的目的,雖然現(xiàn)在我們理解的通信都是這樣經(jīng)過中轉(zhuǎn)的??梢酝ㄟ^while等循環(huán),不斷向上遍歷,直到找到目標父組件,就在對應(yīng)的組件上觸發(fā)事件。
下面就只element-ui實現(xiàn)的一個父子組件通信的mixins,對于組件同步有很大的作用。在element-ui 的優(yōu)點概述中也特意提到這個組件通信
function broadcast(componentName, eventName, params) {
// 向下遍歷每個子節(jié)點,觸發(fā)相應(yīng)的向下廣播的 事件
this.$children.forEach(child => {
var name = child.$options.componentName;
if (name === componentName) {
child.$emit.apply(child, [eventName].concat(params));
} else {
broadcast.apply(child, [componentName, eventName].concat([params]));
}
});
}
export default {
methods: {
// 向上遍歷父節(jié)點,來獲取指定父節(jié)點,通過$emit 在相應(yīng)的 組件中觸發(fā) eventName 事件
dispatch(componentName, eventName, params) {
var parent = this.$parent || this.$root;
var name = parent.$options.componentName;
// 上面的componentName 需要在每個vue 實例中額外配置自定義屬性 componentName,
//可以簡單替換成var name = parent.$options._componentTag;
while (parent && (!name || name !== componentName)) {
parent = parent.$parent;
if (parent) {
name = parent.$options.componentName;
}
}
if (parent) {
parent.$emit.apply(parent, [eventName].concat(params));
}
},
broadcast(componentName, eventName, params) {
broadcast.call(this, componentName, eventName, params);
}
}
};
首先定義兩個嵌套的組件 f1.vue 和 c1.vue,實例是:
<f1> <c1></c1> </f1>
然后,分別定義兩個父子組件:
c2.vue
<template>
<section>
<button type="button" name="button" @click="dispatchTest">點擊一下,就可以</button>
</section>
</template>
<script type="text/javascript">
import Emitter from "../mixins/emitter";
export default {
name: "c2",
mixins: [Emitter],
componentName:'c2',
methods: {
dispatchTest() {
this.dispatch('f1', 'listenerToC1', false);
}
}
}
</script>
f1.vue
<template type="html">
<div class="outBox-class">
<slot>
</slot>
</div>
</template>
<script type="text/javascript">
import Emitter from "../mixins/emitter";
export default {
name: "f1",
mixins: [Emitter],
componentName: 'f1',
mounted() {
this.$on("listenerToC1", (value) => {
alert(value);
})
}
}
</script>
這樣,就可以在子組件中點擊按鈕,觸發(fā) listenerToC1事件,在父組件中監(jiān)聽到這個事件,
其實更$emit觸發(fā)事件類似。不同之處在于,這里可以多級嵌套,不一定是直接的父子組件都可以觸發(fā)到。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
vue用Object.defineProperty手寫一個簡單的雙向綁定的示例
這篇文章主要介紹了用Object.defineProperty手寫一個簡單的雙向綁定的示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-07-07
Vue在echarts?tooltip中添加點擊事件案例詳解
本文主要介紹了Vue項目中在echarts?tooltip添加點擊事件的案例詳解,代碼具有一定的價值,感興趣的小伙伴可以來學(xué)習(xí)一下2021-11-11
基于vue+ bootstrap實現(xiàn)圖片上傳圖片展示功能
這篇文章主要介紹了基于vue+ bootstrap實現(xiàn)圖片上傳圖片展示功能,需要的朋友可以參考下2017-05-05
Vue無后端配合實現(xiàn)導(dǎo)出功能的示例代碼
這篇文章主要為大家詳細介紹了Vue如何在無后端配合的情況下實現(xiàn)導(dǎo)出功能,文中的示例代碼簡潔易懂,有需要的小伙伴可以跟隨小編一起了解一下2024-01-01
15 分鐘掌握vue-next函數(shù)式api(小結(jié))
這篇文章主要介紹了15 分鐘掌握vue-next函數(shù)式api(小結(jié)),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-10-10

