前言
这几天准备加深一下自己对Vue的理解,所以决定开始看Vue的源码,看到了事件模型,觉得可以很好地锻炼自己的思维能力,所以就手写下来了,现在分享给大家,希望有所帮助。
功能
事件模型有包括三个功能函数:on、off、emit。on事件函数负责注册各种事件,off事件函数负责注销已经注册的函数,emit事件函数负责触发已经注册的函数。这些功能是很常用的。
代码
把这个代码写在一个立即执行函数中,这样可以防止变量污染,虽然写这个功能也没啥可以污染的,但是也要养成良好的编码习惯不是_。
var event = {
var eventObjs = {};
return {
on:function() {},
off:function() {},
emit:function() {}
}
}
eventObjs这个对象用来记录我们注册的事件名和事件函数,它的内部是这样的:
对象的键是事件名,值是一个数组,里面记录着所有这个类型的函数
实现on
on事件时最简单的,一行代码就可以实现:
on:function(type, hanlder){
//判断有没有这个类型的事件,没有就设置为空数组,有就push进去函数
//为啥要这样写呢, 因为源码中就是这样写的,而且我觉得很好用
(eventObjs[type] || (eventObjs[type] = [])).push(hanlder);
}
这行代码的意思是,先判断eventObjs[type]存不存在,如果存在就不看第二项了,直接push这个函数,如果不存在,就走第二项,创建一个这个类型的数组,然后再push这个函数。
实现off
off:function(type, handler){
if(!eventObjs[type]) return;
if(arguments.length === 0){
//没有传参数,全部清除
eventObjs = {};
}else if(arguments.length === 1){
//传了一个参数,代表清除这个事件名的函数
eventObjs[type] = [];
}else if(arguments.length === 2){
//传了两个参数,代表清除这个事件名的某个函数
let _events = eventObjs[type];
if(!_events) return;
for(var i = _events.length; i >= 0; i--){//从后向前循环,删除数组中的元素,索引不会改变
if(_events[i] === hanlder){
_events[i].splice(i, 1);
}
}
}
}
off这个事件可以不传递参数,可以传递一个参数,也可以传递两个参数,意思分别是:
0个参数:注销所有函数
1个参数:注销这个type类型的所有函数
2个参数:注销这个type类型的handler函数
实现emit
emit:function(type){
//获取传入的参数
let args = Array.prototype.slice.call(arguments, 1);
if(!eventObjs[type]) return;
let _events = eventObjs[type];
if(!_events) return;
for(var j = 0; j < _events.length; j++){
_events[j].apply(null, args);
}
}
emit事件是触发某个类型的函数,这个事件可以给触发的函数传递参数,因此,首先要获取传入的参数,在下面执行这个函数的时候将参数传递过去,如果有上下文,就把null替换成相应的上下文就行,没有就用null。
结语
刚开始自己尝试封装已经存在的API的时候,是很困难的,不知从何下手,看别人的代码也看到晕晕乎乎,但是做得多了之后,慢慢就有了感觉。 加油!共勉!
全部源码
var event = (function (){
var eventObjs = {};
return {
on:function(type, hanlder){
//判断有没有这个类型的事件,没有就设置为空数组,有就push进去函数
(eventObjs[type] || (eventObjs[type] = [])).push(hanlder);
},
off:function(type, handler){
if(!eventObjs[type]) return;
if(arguments.length === 0){
//没有传参数,全部清除
eventObjs = {};
}else if(arguments.length === 1){
//传了一个参数,代表清除这个事件名的函数
eventObjs[type] = [];
}else if(arguments.length === 2){
//传了两个参数,代表清除这个事件名的某个函数
let _events = eventObjs[type];
if(!_events) return;
for(var i = _events.length; i >= 0; i--){//从后向前循环,删除数组中的元素,索引不会改变
if(_events[i] === hanlder){
_events[i].splice(i, 1);
}
}
}
},
emit:function(type){
//获取传入的参数
let args = Array.prototype.slice.call(arguments, 1);
if(!eventObjs[type]) return;
let _events = eventObjs[type];
if(!_events) return;
for(var j = 0; j < _events.length; j++){
_events[j].apply(null, args);
}
}
}
}())