VUE - part7 - Event
看这篇之前,如果没有看过之前的文章,可拉到文章末尾查看之前的文章。
事件是什么?
在标准浏览器中,我们经常使用:addEventListener 来为一个 DOM 添加一个事件(click、mousemove、tap等)。
在我看来,一个事件是一种行为(或情况),当发生这种行为(或情况)时,我们要去做的事,比如今天下雨了,那我就得去找伞;闹钟响了,那我就得起床等等。
仔细看这些情况,归结到代码中,无非就是一个行为(或情况)的名称,和一些列的动作,而在 js 中动作就是 function,一系列的动作就是一个函数的集合。
实现
如上所说,我们把事件抽象成一个类
类下属性 & 方法
- _events 一个对象 {key: eventName, value: Array<Function,Function...>}
 - $on(eventName, func) 添加具体事件的处理函数
 - $off(eventName) 取消事件处理函数
 - $emit(eventName, data1, data2, ...) 用于触发事件
 - $once(eventName, func) 设置仅触发一次的事件
 
ok 根据我们的构想,在来看这个实现好的 Event 类
let uid = 0
export class Event {
    constructor() {
        this.id = ++uid
        this._events = {}
    }
    $on(eventName, fn) {
        let ctx = this;
        // 若 _events 对象下无对应事件名,则新建一个数组,然后将处理函数推入数组
        if(!ctx._events[eventName]){
            ctx._events[eventName] = []
        }
        ctx._events[eventName].push(fn)
        return ctx
    }
    $once(eventName, fn) {
        let ctx = this
        function on() {
            // 先取消,然后触发,确保仅触发一次
            ctx.$off(eventName, on)
            fn.apply(ctx, arguments)
        }
        on.fn = fn
        ctx.$on(eventName, on)
        return object
    }
    $off(eventName) {
        let ctx = this
        const cbs = ctx._events[eventName]
        if (cbs) {
            // 取消置空即可
            ctx._events[eventName] = null
        }
        return ctx
    }
    $emit(eventName, ...args) {
        let ctx = this
        let cbs = ctx._events[eventName]
        if (cbs) {
            cbs.forEach(func => func.apply(ctx, args))
        }
        return ctx
    }
}
一个简单的事件管理的类便实现好了,让我们来测试一下:
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 一个简易的事件管理实现了,由于这节内容与上几节关系不大,所以这里再次说下测试代码的运行方式:
node环境8.11.1往上,不然不能够支持import语法- 为了不转码支持 
import语法,文件后缀为.mjs - 进入到 
test.mjs所在目录命令行运行:node --experimental-modules test.mjs即可 
系列文章地址
- VUE - MVVM - part1 - defineProperty
 - VUE - MVVM - part2 - Dep
 - VUE - MVVM - part3 - Watcher
 - VUE - MVVM - part4 - 优化Watcher
 - VUE - MVVM - part5 - Observe
 - VUE - MVVM - part6 - Array
 - VUE - MVVM - part7 - Event
 - VUE - MVVM - part8 - 优化Event
 - VUE - MVVM - part9 - Vue
 - VUE - MVVM - part10 - Computed
 - VUE - MVVM - part11 - Extend
 - VUE - MVVM - part12 - props
 - VUE - MVVM - part13 - inject & 总结