VUE 中 MVVM – step7 – Event

aco發表於2018-04-23

雖然實現 VueMVVM 已經走到第 7 步,但這節內容與之前的內容相關性不大,但若想要了解整個 MVVM 的實現,還是先移步看之前已經實現的 6

  1. 簡單實現 VUE 中 MVVM – step1 – defineProperty
  2. 簡單實現 VUE 中 MVVM – step2 – Dep
  3. 簡單實現 VUE 中 MVVM – step3 – Watcher
  4. 簡單實現 VUE 中 MVVM – step4 – 優化Watcher
  5. 簡單實現 VUE 中 MVVM – step5 – Observe
  6. 簡單實現 VUE 中 MVVM – step6 – Array

事件是什麼?

在標準瀏覽器中,我們經常使用:addEventListener 來為一個 DOM 新增一個事件(clickmousemovetap等)。

在我看來,一個事件是一種行為(或情況),當發生這種行為(或情況)時,我們要去做的事,比如今天下雨了,那我就得去找傘;鬧鐘響了,那我就得起床等等。

仔細看這些情況,歸結到程式碼中,無非就是一個行為(或情況)的名稱,和一些列的動作,而在 js 中動作就是 function,一系列的動作就是一個函式的集合。

實現

如上所說,我們把事件抽象成一個類

類下屬性 & 方法

  • _events/Object: 用於存放事件名稱(key/String)和一些列的動作(value/Array<Function,Function…>)
  • $on(eventName, func)/Function: 用於新增具體事件的處理函式
  • $off(eventName)/Function: 既然有新增肯定是有取消
  • $emit(eventName, data1, data2, …)/Function: 用於觸發事件
  • $once(eventName, func)/Function: 用於新增僅僅觸發一次的事件,作為一個語法糖的存在,比如你想在特定時間設定一個鬧鐘,顯然這個鬧鐘並不是你的起床鬧鐘,僅僅需要觸發一次就夠了

ok 根據我們的構想,在來看這個實現好的 Event

let uid = 0

export class Event {
    constructor() {
        this.id = ++uid
        this._events = {}
    }

    $on(eventName, fn) {
        let object = this;
        // 若 _events 物件下無對應事件名,則新建一個陣列,然後將處理函式推入陣列
        (object._events[eventName] || (object._events[eventName] = [])).push(fn)
        return object
    }

    $once(eventName, fn) {
        let object = this

        function on() {
            // 先取消,然後觸發,確保僅觸發一次
            object.$off(eventName, on)
            fn.apply(object, arguments)
        }

        on.fn = fn
        object.$on(eventName, on)
        return object
    }

    $off(eventName) {
        let object = this
        const cbs = object._events[eventName]
        if (cbs) {
            // 取消置空即可
            object._events[eventName] = null
        }
        return object
    }

    $emit(eventName, ...args) {
        let object = this
        let cbs = object._events[eventName]
        if (cbs) {
            cbs.forEach(func => func.apply(object, args))
        }
        return object
    }

}

一個簡單的事件管理的類便實現好了,讓我們來測試一下:

import {Event} from "./Event";

let eventTest = new Event()

eventTest.$on(`testEvent`, function (event) {
    console.log(`測試事件新增,傳入引數為` + event)
})

eventTest.$emit(`testEvent`, `事件觸發成功`)
// 測試事件新增,傳入引數為事件觸發成功

eventTest.$emit(`testEvent`, `事件再次觸發成功`)
// 測試事件新增,傳入引數為事件再次觸發成功

eventTest.$off(`testEvent`)

eventTest.$emit(`testEvent`, `事件取消,不會有輸出`)
// 無輸出

eventTest.$once(`testOnce`, function (event) {
    console.log(`事件僅僅觸發一次,傳入引數為` + event)
})

eventTest.$emit(`testOnce`, `事件觸發成功`)
// 事件僅僅觸發一次,傳入引數為事件觸發成功

eventTest.$emit(`testOnce`, `事件取消,不會有輸出`)
// 無輸出

ok 一個簡易的事件管理實現了,由於這節內容與上幾節關係不大,所以這裡再次說下測試程式碼的執行方式:

  1. node 環境 8.11.1 往上,不然不能夠支援 import 語法
  2. 為了不轉碼支援 import 語法,檔案字尾為 .mjs
  3. 進入到 test.mjs 所在目錄命令列執行:node --experimental-modules test.mjs 即可

點選檢視相關程式碼

更多內容,可以訪問http://blog.acohome.cn

相關文章