Vue中$on和$emit的實現原理分析
Vue中發佈訂閱模式
在Vue中采用瞭發佈訂閱模式,典型的兄弟組件間的通信$on和$emit
發佈訂閱模式:(訂閱者、發佈者、信號中心)
一個發佈者$emit發佈一個事件到信號中心 eventBus ,訂閱者們 $on 通過信號中心收到該事件,進行處理
在這裡模擬一個自定義事件 $on和$emit事件
class EventBus{ constructor(){ // 1.處理事件對應的處理函數 this.sub = {} } $on(event,fn){ if(!this.sub[event]){ // 2.判斷sub是否已經存在該事件瞭,沒有的話就賦值一個數組,用來存儲觸發函數 this.sub[event] = [] } // 3.將函數push到對應的事件中 this.sub[event].push(fn) } $emit(event){ if(this.sub[event]){ this.sub[event].forEach(fn=>{ fn() //4.執行對應事件中的處理函數 }) } } } // 信號中心 const vm = new EventBus() // 訂閱事件 vm.$on('click',()=>{console.log('觸發瞭click事件')}) vm.$on('change',()=>{console.log('觸發瞭change事件')}) // 發佈訂閱 vm.$emit('click') vm.$emit('change')
$emit和$on用法深挖
俗稱的 e m i t 和 emit和 emit和on就是消費和定義,咱們在代碼中講解
<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的原理實現
先在create加個斷點
我們會發現他會跳到on的源碼中
我們傳入的參數是兩個,第一個是我們事件的名稱,第二個是我們事件處理方法對應的event和fn
- 首先他把this傳給vm
- 然後判斷event是不是一個數組,如果是個數組他就會以循環的方式進行賦值,繼續執行on的迭代方法,如果不是數組進入else的邏輯判斷去找他是不是包含瞭event,如果不包含他會自己創建個event設置成空數組,把新建的處理函數push進去,這說明我們在定義個事件的時候,是可以同時為一個事件定義多個執行方法,最後找到定義的方法並返回
- 定義第二種方法看代碼
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') } } });
說明定義多個執行方法也是沒問題的
有一點要記住先定義的先觸發
還有一個點他是可以是個數組,在不同的事件綁定同一個處理方法,如下代碼
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') } } });
換成第二個數組他還是可以實現
分析$emit
先打個斷點
1.emit的源碼
2.關鍵的一步:先通過名稱改成小寫後然後直接從我們vue實例下劃線events這個對象當中拿出事件對應的方法,如果找不到什麼都不做,直接返回回來,找的話,第一步先判斷cbs的長度打不打與1,因為他有可能是個數組,多個處理函數如果大於一就變成瞭一個數組,如果等於一的話直接返回cbs.
第二步他對arguments做瞭處理把後面的參數變成數組,第一個不要瞭 ,因為事件名稱他用完瞭,緊接著他對cbs做瞭個循環,
這個函數是捕獲處理異常,執行try catch,所以說如果執行emit出瞭錯誤他不會崩潰,會拋出錯誤,這個地方做的還不賴 最後把res返回
總結
可以通過源碼去理解事半功倍噢
通過源碼分析我們會知道on方法在定義的時候他可以定義多個事件,也可以為同個事件綁定多個處理函數,在定義中還可以是數組
在emit當中進行trycate的處理,所以我們拋出異常的時候我們不會中斷整個程序而崩潰
以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。
推薦閱讀:
- vue中的eventBus會不會產生內存泄漏你知道嗎
- vue給對象添加屬性沒有響應式的問題及解決
- vue中組件之間相互通信傳值的幾種方法詳解
- 超實用vue中組件間通信的6種方式(最新推薦)
- Vue組件通信方式(父傳子、子傳父、兄弟通信)