在 Vue 2.X 中,$dispatch 和 $broadcast 方法已經被廢棄。官方認為基于組件樹結構的事件流方式難以理解,并且在組件結構擴展時容易變得脆弱。因此,Vue 2.X 推薦使用其他方式來實現組件間的通信,例如通過 $emit 和 $on 方法,或者使用事件總線(Event Bus)
子組件向上派發事件 ,然后父組件會收到來自子組件發來的信息
<div id="app"><div><my-fade></my-fade></div>
</div>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.13/vue.js"></script>
<script>//子組件const ChildComponent={template:`<div><h4>子組件</h4><button @click="dispatchEvent">派發事件</button></div>`, //模板,創建一個點擊事件引用模式中的方法dispatchEventmethods:{//事件函數dispatchEvent(){//設置或叫創建自定義事件 custom-event,第2個是傳遞自定義事件的參數,傳遞給handleCustomEvent(message)this.$emit('custom-event','Hello my vue,this is from child');}}};const ParentComponent={//在模板中將子組件嵌入其中,并創建自定義custom-event事件綁定函數handleCustomEventtemplate:`<div><h3>父組件</h3><p>接收到消息:{{message}}</p><child-component @custom-event="handleCustomEvent"></child-component></div>`,data(){return {message:''};},methods:{//這里的參數message就是自定義事件中custom-event的參數handleCustomEvent(message){this.message=message;console.log(this.message);}},components:{// 在父組件中注冊子組件'child-component':ChildComponent} };const app=new Vue({el:"#app",components:{'my-fade':ParentComponent}});
</script>
以下是派發事件,及父組件廣播給所有子組件
<div id="app"><parent-component></parent-component>
</div>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.13/vue.js"></script>
<script>//設置子組件const ChildComponent={template:`<div><h3>子組件</h3><p>接收到消息:{{message}}</p></div> `,data(){return {message:''};},methods:{//主要作為是觸發自定義事件時設置message的值handleBroadcast(message){this.message=message;}},mounted(){//$on主要用途即為監聽自定義事件this.$on('broadcast-event',this.handleBroadcast);},//在組件消毀前移除監聽beforeDestroy(){this.$off('broadcast-event',this.handleBroadcast);}};//設置父組件const ParentComponent={template:`<div><h3>父組件</h3><button @click="broadcastEvent">廣播事件</button><child-component></child-component> //嵌入子組件</div>`,components:{//在父組件中注冊子組件'child-component':ChildComponent},methods:{broadcastEvent(){this.$children.forEach((child)=>{if(child.handleBroadcast){//設置自定義事件broadcast-event,并傳遞hello from Parent這個參數child.$emit('broadcast-event','Hello from Parent')}})}} };const app=new Vue({el:"#app",components:{'parent-component':ParentComponent}})
</script>
廣播事件的典型使用場景
- 表單驗證
場景描述:在復雜的表單中,可能有多個子組件負責不同的表單字段驗證。父組件可以通過廣播事件通知所有子組件進行驗證操作。
實現方式:父組件觸發一個廣播事件(如 validate),所有子組件監聽該事件并執行各自的驗證邏輯。
- 更新狀態
場景描述:父組件需要更新多個子組件的狀態,例如在購物車頁面中,父組件需要通知所有子組件更新商品數量或價格。
實現方式:父組件廣播一個事件(如 update-cart),子組件監聽該事件并根據傳遞的數據更新自身狀態。
- 動態數據同步
場景描述:在多級嵌套的組件結構中,父組件需要將動態數據同步到多個子組件中。
實現方式:父組件通過廣播事件將數據傳遞給所有子組件,子組件接收數據并更新視圖。
- UI 狀態更新
場景描述:父組件需要統一更新多個子組件的 UI 狀態,例如在多級菜單中,父組件需要通知所有子菜單項更新顯示狀態。
實現方式:父組件廣播一個事件(如 toggle-menu),子組件監聽該事件并根據傳遞的參數更新顯示狀態。
- 數據刷新
場景描述:在數據列表中,父組件需要通知所有子組件刷新數據,例如在用戶管理頁面中,父組件需要通知所有子組件重新加載用戶數據。
實現方式:父組件廣播一個事件(如 refresh-data),子組件監聽該事件并調用數據加載方法。
- 示例:表單驗證場景
假設有一個表單,包含多個子組件,每個子組件負責一個表單字段的驗證。父組件需要在提交表單時觸發所有子組件的驗證邏輯。
<div id="app"><form-component></form-component>
</div>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.13/vue.js"></script>
<script>const FieldComponent={//從父組件中獲取到field,pwd,pwd2他們的值//@blur失去焦點時觸發props:['field','pwd','pwd2'],template:`<div><label :for="field.id">{{field.label}}</label><input :id="field.id" v-model="field.value" :type="field.type" :name="field.id" @blur="validateField" autocomplete="false"><span v-if="field.error" style="color:red;">{{field.error}}</span></div>`,methods:{//驗證函數validateField(){if(!this.field.value){this.field.error='此字段必填';}else{switch(this.field.id){case 'username':if(this.field.value.length<4 || this.field.value>21){this.field.error='用戶名字符在4-21之間';}else{this.field.error='';}break;case 'pwd':let regex=/[A-Z]/g;if(this.field.value.length<6 || !regex.test(this.field.value)){this.field.error='密碼必須大于6個字符,并包含大寫字母';}else{this.field.error='';console.log(this.field.value);//設置自定義更新事件,即pwd更新時觸發this.$emit('update:pwd',this.field.value);} break;case 'pwd2':if(this.field.value != this.pwd){this.field.error='兩次密碼不一致';}else{this.field.error='';} break;case 'email':if(!this.field.value.includes('@')){this.field.error='郵箱不正確';}else{this.field.error='';} break;}}}},mounted(){//監聽自定義validate事件,并觸發驗證函數this.$on('validate',this.validateField);},//在消毀前注銷掉事件beforDestroy(){this.$off('validate',this.validateField);} };const FormComponent={//父組件模板,嵌入子組件<field-component 并循環fields數據//@update:pwd即自定義更新事件,getPwd為函數用于設置pwd更新后的值,也可以直接寫成@update:pwd="pwd=$event"template:`<form @submit.prevent="submitForm"><field-component v-for="field in fields" :key="field.id" :field="field" :pwd="pwd" :pwd2="pwd2" @update:pwd="getPwd"></field-component><button type='submit'>提交</button></form> `,components:{//注冊字段子組伯'field-component':FieldComponent} ,data(){return{fields:[{id:'username',label:'用戶:',type:'text',value:'',error:''},{id:'pwd',label:'密碼:',type:'password',value:'',error:''},{id:'pwd2',label:'重復:',type:'password',value:'',error:''},{id:'email',label:'郵箱:',type:'email',value:'',error:''}],pwd:'', //pwd,pwd2主要作用是為了在驗證他們是否相等時使用pwd2:''}},methods:{//在提交時觸發的函數submitForm(){this.$children.forEach((child)=>{if(child.validateField){//在子組件中觸發自定義的驗證函數child.$emit('validate');}});//如果在有一個field.error為真,即會大子組件字段中顯示const hasErrors=this.fields.some((field)=>field.error);if(!hasErrors){alert('表單提交成功');}},getPwd(val){this.pwd=val;}} }const app=new Vue({el:"#app",components:{'form-component':FormComponent}});
</script>
- @update:pwd:
@ 是 Vue 中用于監聽事件的簡寫符號。
update:pwd 是一個自定義事件名稱。update 是一個常見的前綴,用于表示數據更新的事件,而 pwd 是具體的字段名。
- pwd = $event:
pwd 是父組件 FormComponent 中定義的數據屬性。
e v e n t 是 V u e 中的一個特殊變量,表示事件觸發時傳遞的參數。在這里, event 是 Vue 中的一個特殊變量,表示事件觸發時傳遞的參數。在這里, event是Vue中的一個特殊變量,表示事件觸發時傳遞的參數。在這里,event 是子組件 FieldComponent 通過 $emit(‘update:pwd’, this.field.value) 發出的值。
pwd = $event 是一個表達式,表示將子組件發出的值賦值給父組件的 pwd 屬性。