Vue 源碼學習 --事件 event

1. 事件概述

Vue 中的事件可以分爲 2 類:原生 DOM 事件、自定義事件。兩者在使用方式、用途、源碼處理的實現上存在區別。

使用方式:
原生 DOM 事件可用在原生 DOM 元素上,也可用在組件上(這種情況下,需使用 .native 修飾符);自定義事件只能在組件上使用。
用途:
它們都具有事件的基本用途 – 界面與用戶交互;而自定義事件還經常用於父子組件之間的通信
源碼實現:
原生 DOM 事件的處理主要依靠原生的 addEventListenerremoveEventListener 來完成;而自定義事件則是通過事件中心的模型處理的。

2. 代碼實現基本事件中心

Vue 中的事件處理,主要有 vm.$on、vm.$off、vm.$emit、vm.$once 這四個方法:

vm.$on:
監聽當前實例上的自定義事件。

vm.$off:
移除自定義事件監聽器。
如果沒有提供參數,則移除所有的事件監聽器;
如果只提供了事件,則移除該事件所有的監聽器;
如果同時提供了事件與回調,則只移除這個回調的監聽器。

vm.$emit:
觸發當前實例上的事件。附加參數都會傳給監聽器回調。

vm.$once:
監聽一個自定義事件,但是隻觸發一次。一旦觸發之後,監聽器就會被移除。

下面是實現基礎功能的代碼部分:

class EventBus {
        constructor() {
          // 事件中心的核心
          // 存儲所有的事件名稱以及對應的事件處理函數列表
          this._events = {};
        }

        // vm.$on(event, callback)
        // 根據事件名稱 event,將事件回調放進對應的列表 
        on(event, callback) {
          (this._events[event] || (this._events[event] = [])).push(callback);
        }

        // vm.$off([event, callback])
        off() {
          let _args = [...arguments];
          let length = _args.length;
          switch (length) {
            case 0: // 移除所有的事件的回調函數
              for (let event in this._events) {
                this._events[event] = [];
              }
              break;
            case 1: // 移除特定事件的事件回調列表
              let _event0 = _args[0];
              for (let event in this._events) {
                if (_event0 === event) {
                  this._events[event] = [];
                }
              }
              break;
            default: // 移除指定特定事件下的特定的事件回調
              let _event = _args[0];
              let _callback = _args[1];
              for (let event in this._events) {
                if (_event === event) {
                  this._events[event].map((item, index) => {
                    if (item.toString() === _callback.toString()) {
                      this._events[event].splice(index, 1);
                    }
                  });
                }
              }
          }
        }

        // vm.$emit(eventName, [...args])
        // 找到指定事件名稱的回調函數列表,遍歷且執行回調
        emit(eventName) {
          let callbacks = this._events[eventName];
          let params = [...arguments].slice(1);
          callbacks &&
            callbacks.map((_callback) => {
              _callback(...params);
            });
        }

        // vm.$once(event, callback)
        // 根據事件名稱 event,將事件回調放進對應的列表;且該回調被執行一次後,就會移除
        once(event, callback) {
		  let that = this
          function _on() {
           // 移除事件處理回調函數
            that.off(event, _on);
            // 使用參數,調用回調
            callback.apply(that, arguments);
          }
		  that.on(event, _on);
        }
      }

接下來,創建出 EventBus 實例後,就可以使用功能了,下面是一些簡單的測試:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章