Vue中$on和$emit的實(shí)現(xiàn)原理分析
Vue中發(fā)布訂閱模式
在Vue中采用了發(fā)布訂閱模式,典型的兄弟組件間的通信$on和$emit
發(fā)布訂閱模式:(訂閱者、發(fā)布者、信號中心)
一個發(fā)布者$emit發(fā)布一個事件到信號中心 eventBus ,訂閱者們 $on 通過信號中心收到該事件,進(jìn)行處理
在這里模擬一個自定義事件 $on和$emit事件
class EventBus{ constructor(){ // 1.處理事件對應(yīng)的處理函數(shù) this.sub = {} } $on(event,fn){ if(!this.sub[event]){ // 2.判斷sub是否已經(jīng)存在該事件了,沒有的話就賦值一個數(shù)組,用來存儲觸發(fā)函數(shù) this.sub[event] = [] } // 3.將函數(shù)push到對應(yīng)的事件中 this.sub[event].push(fn) } $emit(event){ if(this.sub[event]){ this.sub[event].forEach(fn=>{ fn() //4.執(zhí)行對應(yīng)事件中的處理函數(shù) }) } } } // 信號中心 const vm = new EventBus() // 訂閱事件 vm.$on('click',()=>{console.log('觸發(fā)了click事件')}) vm.$on('change',()=>{console.log('觸發(fā)了change事件')}) // 發(fā)布訂閱 vm.$emit('click') vm.$emit('change')
$emit和$on用法深挖
俗稱的 e m i t 和 emit和 emit和on就是消費(fèi)和定義,咱們在代碼中講解
<body> <div id="app"> <button @click="add">測試</button> </div> <script> var vm = new Vue({ el: '#app', data: { message:'ok' }, created() { this.$on('my_event',this.datalist) }, methods: { datalist(e){ console.log(this.message,e); }, add(){ this.$emit('my_event','hello wu') } } }); </script> </body>
首先剖析一下$on的原理實(shí)現(xiàn)
先在create加個斷點(diǎn)
我們會發(fā)現(xiàn)他會跳到on的源碼中
我們傳入的參數(shù)是兩個,第一個是我們事件的名稱,第二個是我們事件處理方法對應(yīng)的event和fn
- 首先他把this傳給vm
- 然后判斷event是不是一個數(shù)組,如果是個數(shù)組他就會以循環(huán)的方式進(jìn)行賦值,繼續(xù)執(zhí)行on的迭代方法,如果不是數(shù)組進(jìn)入else的邏輯判斷去找他是不是包含了event,如果不包含他會自己創(chuàng)建個event設(shè)置成空數(shù)組,把新建的處理函數(shù)push進(jìn)去,這說明我們在定義個事件的時候,是可以同時為一個事件定義多個執(zhí)行方法,最后找到定義的方法并返回
- 定義第二種方法看代碼
var vm = new Vue({ el: '#app', data: { message:'ok' }, created() { this.$on('my_event',this.datalist) this.$on('my_event',this.datalist2) }, methods: { datalist(e){ console.log(this.message,e); }, datalist2(e){ console.log('我是第二種方法',e); }, add(){ this.$emit('my_event','hello wu') } } });
說明定義多個執(zhí)行方法也是沒問題的
有一點(diǎn)要記住先定義的先觸發(fā)
還有一個點(diǎn)他是可以是個數(shù)組,在不同的事件綁定同一個處理方法,如下代碼
var vm = new Vue({ el: '#app', data: { message:'ok' }, created() { this.$on(['my_event','my_event2'],this.datalist) console.log(this._events); // this.$on('my_event',this.datalist2) }, methods: { datalist(e){ console.log(this.message,e); }, datalist2(e){ console.log('我是第二種方法',e); }, add(){ this.$emit('my_event2','hello wu') } } });
換成第二個數(shù)組他還是可以實(shí)現(xiàn)
分析$emit
先打個斷點(diǎn)
1.emit的源碼
2.關(guān)鍵的一步:先通過名稱改成小寫后然后直接從我們vue實(shí)例下劃線events這個對象當(dāng)中拿出事件對應(yīng)的方法,如果找不到什么都不做,直接返回回來,找的話,第一步先判斷cbs的長度打不打與1,因?yàn)樗锌赡苁莻€數(shù)組,多個處理函數(shù)如果大于一就變成了一個數(shù)組,如果等于一的話直接返回cbs.
第二步他對arguments做了處理把后面的參數(shù)變成數(shù)組,第一個不要了 ,因?yàn)槭录Q他用完了,緊接著他對cbs做了個循環(huán),
這個函數(shù)是捕獲處理異常,執(zhí)行try catch,所以說如果執(zhí)行emit出了錯誤他不會崩潰,會拋出錯誤,這個地方做的還不賴 最后把res返回
總結(jié)
可以通過源碼去理解事半功倍噢
通過源碼分析我們會知道on方法在定義的時候他可以定義多個事件,也可以為同個事件綁定多個處理函數(shù),在定義中還可以是數(shù)組
在emit當(dāng)中進(jìn)行trycate的處理,所以我們拋出異常的時候我們不會中斷整個程序而崩潰
以上為個人經(jīng)驗(yàn),希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
vue中如何使用唯一標(biāo)識uuid(uuid.v1()-時間戳、uuid.v4()-隨機(jī)數(shù))
這篇文章主要給大家介紹了關(guān)于vue中如何使用唯一標(biāo)識uuid(uuid.v1()-時間戳、uuid.v4()-隨機(jī)數(shù))的相關(guān)資料,當(dāng)使用Vue.js生成UUID時,我們可以使用uuid庫來幫助我們生成通用唯一標(biāo)識符(UUID),需要的朋友可以參考下2023-12-12uniapp微信小程序axios庫的封裝及使用詳細(xì)教程
這篇文章主要給大家介紹了關(guān)于uniapp微信小程序axios庫的封裝及使用的相關(guān)資料,Axios是一個基于promise網(wǎng)絡(luò)請求庫,作用于node.js和瀏覽器中axios-miniprogram-adapteraxios的小程序適配器,需要的朋友可以參考下2023-08-08vue-router的導(dǎo)航守衛(wèi)使用最新講解
這篇文章主要介紹了vue-router的導(dǎo)航守衛(wèi)使用講解,vue-router提供了許多編程式導(dǎo)航的API,其中最常見的導(dǎo)航API有很多種,本文給大家詳細(xì)講解,需要的朋友可以參考下2022-12-12用 Vue.js 遞歸組件實(shí)現(xiàn)可折疊的樹形菜單(demo)
通過本文給您演示一下如何有效地使用遞歸組件,我將通過建立一個可擴(kuò)展/收縮的樹形菜單的來一步步進(jìn)行。下面通過本文給大家分享用 Vue.js 遞歸組件實(shí)現(xiàn)可折疊的樹形菜單,需要的朋友參考下吧2017-12-12