微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Javascript自定义事件详解

Javascript自定义事件,其本质就是观察者模式(又称订阅/发布模式),它的好处就是将绑定事件和触发事件相互隔离开,并且可以动态的添加删除事件。

下面通过实例,一步一步构建一个具体的Javascript自定义事件对象。

如:我有一个action1函数,我想每次在执行完action1后,触发另一个函数service1,那么代码我们可以这么写:

rush:js;"> //服务service1 function service1(){

}
//函数action1
function action1(){
//other things
//then 启动service1
service1();
}

Good,但是现在想法变了,我想在action1完成后,不仅触发service1,还要触发service2和service3。

按照刚才的思路,在函数action1完成后,顺带加上它们就是了。

如下:

rush:js;"> function service1(){} function service2(){} function service3(){}

function action1(){
//other things
service1();
service2();
service3();
}

但,想法又再次发生波动,在执行完action1函数后,我突然想动态添加一个service4,且,发现service2似乎毫无意义,我不想触发了,怎么办呢?

你可能会说去掉service2,然后在action1后面加入service4不就完了吗?

但是,在真正的项目开发代码日益剧增的情况下,谈何容易,还要去找到相关代码进行操作。

那怎么办呢?

初步想法,定义一个数组嘛(如:servicearray),用来管理所有的service。

当action1执行到末尾后,遍历一遍这个数组函数(servicearray),就欧克了嘛。

且,倘若我们不想运行service2了,便将它从这个数组中删除就好了;倘若想再添加一个新的service,将其追加到servicearray数组中就好了。

如此nice,如下:

rush:js;"> var servicearray = [];

function service1(){}
function service2(){}
function service3(){}
//将所有service添加到servicearray中
servicearray.push(service1);
servicearray.push(service2);
servicearray.push(service3);
//del:用于删除一个指定的service
function del(arr,fn){
for(var i = 0; i < arr.length; i++){
if( arr[i] == fn ){
arr.splice(i,1);
break;
}
}
}
//action1后,执行所有的service
function action1(){
//other things
//遍历serviceaary,执行所有service函数。(servicearray在action1内)
for(var i =0; i < servicearray.length; i++){
servicearray[i]();
}
}
//添加service4
function service4(){}
servicearray.push(service4);
//删除service2
del(servicearray,service2);

上面代码挺欧克的,但,复用性一点都不强,且servicearray与action你中有我,我中有你,不好。我们再来优化优化。

代码如下:

rush:js;"> var servicearray = [];

function service1(){}
function service2(){}
function service3(){}

servicearray.push(service1);
servicearray.push(service2);
servicearray.push(service3);
function del(arr,1);
break;
}
}
}
//添加一个service4
function service4(){}
servicearray.push(service4);
//删除一个service2
del(servicearray,service2);
//添加一个触发函数hanldeAction,分离action与service
function hanldeAction(actionName,serviceArr){
if(typeof actionName === 'function'){
actionName();
for(var i =0; i < serviceArr.length; i++){
serviceArr[i]();
}
}
}
//执行
handleAction(action1,servicearray);

上面的代码和回调函数有异曲同工之处,因为我们想达到的效果是在 action执行完成之后,运行一系列service嘛。

但,我现在改变想法了,我想在action执行之前执行一系列service呢,或者action中呢。看来得改hanldeAction回调函数啊,这放在项目中反复修改,显然不行。

所以,我们得让其更强大才好。(我想让它在什么地方执行就执行)

如下:

<div class="jb51code">
<pre class="brush:js;">
function service1(){}
function service2(){}
function service3(){}

var servicearray = [];
servicearray.push(service1);
servicearray.push(service2);
servicearray.push(service3);
function del(arr,service2);
/
actionObj用于存储所有action与service关联的对象。
如:{
action1:[service1,service2],action2:[...]
}
/
var actionObj = {};
/
修改代码,增加一个actionName与serviceArr关联事件。
如,action1关联所有service,这样再结合下方的trigger事件就完美了
Params:
actionName --> actionObj的属性
serviceArr --> 包含所有与actionName相关的service数组
/
function addAction(actionName,serviceArr){
if(typeof actionObj[actionName] === 'undefined' ){
actionObj[actionName] = [];
}
if(typeof serviceArr === 'object'){
actionObj[actionName].push(serviceArr);
}
}
/
修改代码增加一个触发actionName事件
如,当我想触发action1中的所有service时,调用trigger(action1)就OK啦
/
function trigger( actionName ){
var act = actionObj[actionName];
if(act instanceof Array){
for(var i = 0,len = act.length; i < len; i++){
for(var j =0,arrlen = act[i].length; j++){
((act[i])[j])();
}
}
}
}

上述代码是可以,但,有个性能问题,addAction中添加到actionObj[actionName]中的是一个数组,其实完全可以将定义的servicearray数组(为了存储不同的service而声明的数组)移除,转而将每个service直接push进actionObj[actionName]声明的数组中,这样trigger事件效率也得到了提高,从原来的两层for循环降到一层for循环。且,我们再加一个删除service的方法remove。

整理代码如下:

rush:js;"> var actionObj = {}; //修改代码增加一个actionName与service函数直接关联事件 function addAction(actionName,fn){ if(typeof actionObj[actionName] === 'undefined' ){ actionObj[actionName] = []; } if(typeof fn === 'function'){ actionObj[actionName].push(fn); } } //修改代码增加一个触发actionName事件 function trigger( actionName ){ var actionarray = actionObj[actionName]; if(actionarray instanceof Array){ for(var i = 0,len = actionarray.length; i < len; i++){ if(typeof actionarray[i] === 'function'){ actionarray[i](); } } } } //修改代码增加一个删除actionName中的service事件 function remove(actionName,fn){ var actionarray = actionObj[actionName]; if(typeof actionName === 'string' && actionarray instanceof Array){ if(typeof fn === 'function'){ //清除actionName中对应的fn方法 for(var i=0,len = actionarray.length; i < len; i++){ if(actionarray[i] === fn){ actionObj[actionName].splice(i,1); } } } } }

上面的代码好是好,action与service也互不影响,也完成了它的使命。

使命?

这就是我们一起编写的自定义事件嘛。是不是很简单。

哈哈哈,我尼玛也在代码中用到设计模式了(观察者模式)。

一鼓作气,我们再来优化下上面的代码。有没有注意,我们是使用的全局变量,在模块化开发的大环境下,我们居然在用全局变量,岂不是污染命名空间嘛。再改改。

修改代码如下:

rush:js;"> var EventTarget = function(){ this.listener = {}; } EventTarget.prototype = { constructor:EventTarget,addAction: function(actionName,fn){ if(typeof actionName === 'string' && typeof fn === 'function'){ //如果不存在actionName,就新建一个 if(typeof this.listener[actionName] === 'undefined'){ this.listener[actionName] = [fn]; } //否则,直接往相应actinoName里面塞 else{ this.listener[actionName].push(fn); } } },trigger: function(actionName){ var actionArray = this.listener[actionName]; //触发一系列actionName里的函数 if(actionArray instanceof Array){ for(var i = 0,len = actionArray.length; i < len; i++){ if(typeof actionArray[i] === 'function'){ actionArray[i](); } } } actionArray = null; },remove: function(actionName,fn){ var actionArray = this.listener[actionName]; if(typeof actionName === 'string' && actionArray instanceof Array){ if(typeof fn === 'function'){ //清除actionName中对应的fn方法 for(var i=0,len = actionArray.length; i < len; i++){ if(actionArray[i] === fn){ this.listener[actionName].splice(i,1); } } } } actionArray = null; } };

一个JavaScript自定义事件新鲜出炉。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程之家。

原文地址:https://www.jb51.cc/js/42540.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐