實現 VUE 中 MVVM – step8 – 優化Event

aco發表於2018-04-25

看這篇前如果沒看過 step7 移步檢視,事件和前 6 步關係不大,主要看下 step7

  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
  7. 實現 VUE 中 MVVM – step7 – Event

回顧

在上一步我們實現了一個簡易的事件管理的類,接下來我們把它給優化下,方便我們的使用。主要優化內容:

  1. 方便為多個事件新增同一個函式
  2. 方便為一個事件新增多個函式
  3. 有針對性的取消事件的函式

第一點和第二點都要修改 $on 函式,所以我們一起改:

之前的程式碼

$on(eventName, fn) {
    let object = this;
    (object._events[eventName] || (object._events[eventName] = [])).push(fn)
    return object
}

優化之後的程式碼

$on(eventName, fn) {
    let object = this
    if (Array.isArray(eventName)) {                               // 處理事件名是陣列的情況
        // 遞迴呼叫 $on 函式
        eventName.forEach(name => this.$on(name, fn))
    } else {
        // 將處理函式統一成陣列方便新增
        if (!Array.isArray(fn)) {                                 // 處理處理函式為陣列的情況
            fn = [fn]
        }
        (object._events[eventName] || (object._events[eventName] = [])).push(...fn)
    }
    return object
}

很簡單的優化,但卻讓 $on 函式更加方便的使用。

接著我們來優化 $off 。我們先看看之前的程式碼:

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

我們只做了清空特定事件,其實我們能做的還有很多,

  1. 清空所有事件
  2. 清空多個事件
  3. 取消特定事件的特定處理函式

優化的細節看程式碼中的註釋

$off(eventName, fn) {
    let object = this
    // 清空所有事件
    if (!arguments.length) {
        object._events = Object.create(null)
        return object
    }
    // 清空多個事件
    if (Array.isArray(eventName)) {
        eventName.forEach(name => this.$off(name, fn))
        return object
    }
    // 若沒有事件對應的函式列表則不用處理
    const cbs = object._events[eventName]
    if (!cbs) {
        return object
    }
    // 清空特定事件
    if (!fn) {
        object._events[eventName] = null
        return object
    }
    // 取消特定事件的特定處理函式
    if (fn) {
        let cb
        let i = cbs.length
        // 處理一次取消多個的情況
        if (Array.isArray(fn)) {
            fn.forEach(fnc => this.$off(eventName, fnc))
        }
        while (i--) {
            cb = cbs[i]
            if (cb === fn || cb.fn === fn) {
                cbs.splice(i, 1)
                break
            }
        }
    }
    return object
}

ok 優化好了,測試一下:

import {Event} from "./Event";

let eventTest = new Event()

eventTest.$on(`eventName1`, (e) => {
    console.log(`一次新增一個處理函式`)
    console.log(e)
})

eventTest.$on(`eventName2`, [(e) => {
    console.log(`一次新增多個處理函式,第一個`)
    console.log(e)
}, (e) => {
    console.log(`一次新增多個處理函式,第二個`)
    console.log(e)
}])

eventTest.$on([`eventName3`, `eventName4`], (e) => {
    console.log(`多個事件新增同一處理函式`)
    console.log(e)
})

eventTest.$on([`eventName5`, `eventName6`], [(e) => {
    console.log(`多個事件新增多個處理函式,第一個`)
    console.log(e)
}, (e) => {
    console.log(`多個事件新增多個處理函式,第二個`)
    console.log(e)
}])

eventTest.$emit(`eventName1`, `傳入引數1`)
// 一次新增一個處理函式
// 傳入引數1
eventTest.$emit(`eventName2`, `傳入引數2`)
// 一次新增多個處理函式,第一個
// 傳入引數2
// 一次新增多個處理函式,第二個
// 傳入引數2
eventTest.$emit(`eventName3`, `傳入引數3`)
// 多個事件新增同一處理函式
// 傳入引數3
eventTest.$emit(`eventName4`, `傳入引數4`)
// 多個事件新增同一處理函式
// 傳入引數4
eventTest.$emit(`eventName5`, `傳入引數5`)
// 多個事件新增多個處理函式,第一個
// 傳入引數5
// 多個事件新增多個處理函式,第二個
// 傳入引數5
eventTest.$emit(`eventName6`, `傳入引數6`)
// 多個事件新增多個處理函式,第一個
// 傳入引數6
// 多個事件新增多個處理函式,第二個
// 傳入引數6
console.log(`------------------------------`)

eventTest.$off(`eventName1`)
eventTest.$off([`eventName2`, `eventName3`])

eventTest.$emit(`eventName1`, `傳入引數1`)
// 無輸出
eventTest.$emit(`eventName2`, `傳入引數2`)
// 無輸出
eventTest.$emit(`eventName3`, `傳入引數3`)
// 無輸出
eventTest.$emit(`eventName4`, `傳入引數4`)
// 多個事件新增同一處理函式
// 傳入引數4
eventTest.$emit(`eventName5`, `傳入引數5`)
// 多個事件新增多個處理函式,第一個
// 傳入引數5
// 多個事件新增多個處理函式,第二個
// 傳入引數5
eventTest.$emit(`eventName6`, `傳入引數6`)
// 多個事件新增多個處理函式,第一個
// 傳入引數6
// 多個事件新增多個處理函式,第二個
// 傳入引數6
console.log(`------------------------------`)

eventTest.$off()
eventTest.$emit(`eventName1`, `傳入引數1`)
// 無輸出
eventTest.$emit(`eventName2`, `傳入引數2`)
// 無輸出
eventTest.$emit(`eventName3`, `傳入引數3`)
// 無輸出
eventTest.$emit(`eventName4`, `傳入引數4`)
// 無輸出
eventTest.$emit(`eventName5`, `傳入引數5`)
// 無輸出
eventTest.$emit(`eventName6`, `傳入引數6`)
// 無輸出
console.log(`------------------------------`)

這兩節吧,事件介紹了下,一個健壯的事件的類也編寫好了,接下來我們把這 8 步實現的內容集合到一個物件下,也就是 Vue 下,敬請期待。

點選檢視相關程式碼

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

相關文章