Vue原理Event-源码版-之-自定义事件

44次阅读

共计 1886 个字符,预计需要花费 5 分钟才能阅读完成。

写文章不容易,点个赞呗兄弟
专注 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧
研究基于 Vue 版本 【2.5.17】

如果你觉得排版难看,请点击 下面链接 或者 拉到 下面 关注公众号 也可以吧

【Vue 原理】Event – 源码版 之 自定义事件

Vue 的自定义事件很简单,就是使用 观察者模式 进行事件的监听和分发

Vue 封装的这个观察者模式,可以说是很完善了,这个可以独立抽取出来的在其他项目中使用的代码,只需要做一点点改动,把事件存储器换个地方(Vue 放在了实例上)

我经常在项目中使用,就是为了解耦或者解决一些异步的问题

今天来详细探索 Vue 的 自定义事件

首先,Vue 的事件存储器放在那里?

没错,放在 vm._events 中

你看,比如你这样监听事件

看到实例上保存了你的事件


1、事件存储器

vm._events

看下这个事件存储器在哪里生成的

首先,实例在初始化的时候,给实例增加一个事件存储器 _events

Vue.prototype._init = function(options) {initEvents(vm);    

    //... 初始化选项数据,解析模板,挂载 dom 等

}

function initEvents(vm) {vm._events = Object.create(null);
}

以后,所有这个实例监听的事件,就都存在这里了

那么,接下来就来看 自定义事件的源码了

下面的源码比较不太属于 Vue 的内容,比较独立,很实用,相信大家也都看得懂,这里主要起一个记录的作用

下面会有四个函数

绑定事件,$on

一次性绑定事件,$once

触发事件,$emit

解绑事件,$off


2、$on

注册事件,接收 事件名和回调,很清楚了,都能看得懂

Vue.prototype.$on = function(event, fn) {    

    var vm = this;   

    if (Array.isArray(event)) {for (var i = 0,l = event.length; i < l; i++) {this.$on(event[i], fn);
        }
    } 
    else {(vm._events[event] || (vm._events[event] = [])).push(fn);

    }    

    // 为了链式调用
    return vm
};

3、$once

单次注册。只监听一次,触发之后马上销毁

它妙就妙在,把回调包装了一下,在 回调执行时,先解绑事件,再调用原回调

Vue.prototype.$once = function(event, fn) {  

    var vm = this;     

    function on() {vm.$off(event, on);
        fn.apply(vm, arguments);
    }

    on.fn = fn;
    vm.$on(event, on);      

   
    // 为了链式调用
    return vm
};

4、$emit

触发事件,接收事件名,然后拿到原本设置的回调,遍历调用

Vue.prototype.$emit = function(event) {  

    var vm = this;    

    var _events= event.toLowerCase();    

    var cbs = vm._events[_events]; 

    if (cbs) {cbs = cbs.length > 1 ? toArray(cbs) : cbs;        
        var args = toArray(arguments, 1);        

        for (var i = 0, l = cbs.length; i < l; i++) {cbs[i].apply(vm, args);
        }

    }    

    // 为了链式调用
    return vm
};

5、$off

取消监听事件或者移除监听回调

接收事件名 和 绑定时的事件回调

很简单的啦

Vue.prototype.$off = function(event, fn) {   

    var vm = this;    

    if (!arguments.length) {vm._events = Object.create(null);        

        return vm
    }    

    // 递归调用
    if (Array.isArray(event)) {for (var i = 0, l = event.length; i < l; i++) {this.$off(event[i], fn);
        }        
        return vm
    } 

    var cbs = vm._events[event];    

    if (!cbs) return vm    

    if (!fn) {vm._events[event] = null;        

        return vm

    }    

    // 去掉特定的函数
    if (fn) {        

        var cb;        

        var len = cbs.length;     

        // 遍历移除相应回调
        while (len--) {cb = cbs[len];            

            if (cb === fn || cb.fn === fn) {cbs.splice(len, 1);                

                break

            }
        }
    }    

    // 为了链式调用
    return vm
};

正文完
 0