应用DOM0级事宜模仿简朴的事宜体系

让我们回到还没有DOM2级事宜要领的年代,那时刻,我们想给某元素绑定一个事宜要领时,是如许做的:

javascriptvar ele=document.getElementById("main");
ele.onclick=function(){
    console.log("做一件事");
}

这就是DOM0级事宜要领,我们须要用XXX.onYYY=ZZZ这类情势来绑定事宜,当点击元素时,会输出“做一件事”,恩,很抱负。

接下来,当我们愿望在点击该元素的时刻再做另一件事怎么办呢?下面如许:

javascriptele.onclick=function(){
   console.log("做第二件事");
}

如许一定不可,因为我们是愿望点击时既输出“做一件事”,又要输出“做第二件事”。而如许的话后面的要领将前面的掩盖掉了,因为XXX.onYYY=ZZZ只能给元素的某个事宜范例(如例子中的click事宜)绑定一个要领ZZZ;这个题目难不到我们,既然如许,那我们就把要做的事变全都放在ZZZ里不就好了么;

javascriptfunction fn1(){
    console.log("做一件事");
}
function fn2(){
   console.log("做第二件事");
}
ele.onclick=function(){
    fn1();
    fn2();
}

接下来,应战来了,那假如我们是愿望在点击元素时做100件差别的事变呢?岂非也是如许用XXX.onYYY=ZZZ情势,将100个要领都在ZZZ里顺次实行吗?明显这是很笨的要领;动一下头脑,很快想到另一个处理计划:
明白以下需求,我们是愿望在点击事宜发作时,实行多个要领,而详细有多少个,一开始时不明白的,那末我们能够用一个数组来保留一切的回调要领;当点击发作时,实行一个要领,在这个要领中顺次实行数组中的回调要领。

javascriptvar arr=[];
ele.onclick=function(){
    for(var i=0;i<arr.length;i++){
        if(typeof arr[i] === "function"){
            arr[i]();
        }
    }
}

arr.push(fn1);
arr.push(fn2);

如许的话,当我们须要给元素点击事宜增加更多的要领时,直接往数组arr中push更多的回调要领就好了,以至当我们愿望去掉某个要领,也能够经由过程删除数组中的某项来完成。
然则如许并不能现实运用,因为用来保留事宜的数组当前是作为一个全局变量。为了耐久化保留这个数组,我们能够如许,将这个数组定义为元素节点对象的某一个属性,就像下面如许:

javascriptele.eventList=[];
ele.onclick=function(){
    for(var i=0;i<btn.eventList.length;i++){
        btn.eventList[i]();
    }
}

ele.eventList.push(fn1);
ele.eventList.push(fn2);

以上代码只是针对click事宜,在现实运用时,有种种差别的事宜范例;在某个范例事宜触发时,须要实行一切绑定到该范例事宜的要领,因而,针对每一个事宜范例,都要采纳一个数组来保留响应回调要领。
别的,为了在某范例事宜触发时,找到针对与该事宜范例的一切要领并实行,我们能够将这个数组直接以事宜范例称号定名;
然后斟酌将以上要领用一个函数封装起来:以下

javascriptfunction bind(ele,ev,callback){
    if(!ele.ev){
        ele.ev=[];//直接将保留某个事宜范例一切回调要领的数组定名为事宜范例
        ele["on"+ev]=function(){
            for(var i=0;i<ele.ev.length;i++){
                ele.ev[i].call(ele);//这里别忘了用call转变this关键字
            }
        }
    }
    ele.ev.push(callback);
}

为了防备反复绑定,在将回调函数push进事宜行列数组时,起首须要推断被绑定的回调是不是已存在于事宜行列中;

javascriptfunction bind(ele,ev,callback){
    if(!ele.ev){
        ele.ev=[];
        ele["on"+ev]=function(){ //只须要绑定一次
            for(var i=0;i<ele.ev.length;i++){
                ele.ev[i].call(ele);//这里别忘了用call转变this关键字
            }
        }
    }

    //因为IE9以下不支持数组的indexOf要领,所以须要遍历查找
    var flag=true;
    for(var i=0;i<ele.ev.length;i++){
        if(ele.ev[i]==callback){
            flag=false;
            break;
        }
    }
    if(flag){
        ele.ev.push(callback);
    }
}

而响应unbind要领,只须要将须要解绑的回调函数从响应的函数行列中删除即可;
别的另有以下一个题目:上述这类情况下,绑定了几个范例的事宜,就会给ele多增加几个属性,定名空间污染极为严峻;所以采纳的计划是在元素上只增加一个属性(如_event),然后一切的事宜行列全都扩大在这个属性上。

悉数代码以下:

完整版代码

javascriptfunction bind(ele,ev,callback){
    if(!ele._event){
        ele._event={};
    }
    if(!ele._event[ev]){
        ele._event[ev]=[];
        ele["on"+ev]=function(e){
            e=e||window.event;

            var eList=ele._event[ev];
            for(var i=0;i<eList.length;i++){
                eList[i].call(ele,e);
            }
        }
    }

    var flag=true;
    for(var i=0;i<ele._event[ev].length;i++){
        if(ele._event[ev][i] == callback){
            flag=false;
            break;
        }
    }
    if(flag){
        ele._event[ev].push(callback);
    }
}


function unbind(ele,ev,callback){
    try{
        var eList=ele._event[ev];
        for(var i=0;i<eList.length;i++){
            if(eList[i]==callback){
                eList.splice(i,1);
                return 1;
            }
        }
    }catch(e){
        //这里重要防备在未挪用bind初始化就挪用unbind时失足。
        console.log("请先运用bind绑定事宜。");
    }
}

在运用时传入三个参数,元素,事宜范例,回调要领,即可。解绑时传入一样的三个参数;这个简朴的计划处理了以下题目:

  1. this关键字指向题目
  2. 反复绑定题目
  3. 实行递次题目

以上,我们就完成了一个粗拙的事宜体系,它的头脑很类似于Dean Edward在其宣布的addEvent.js中的完成体式格局;

    原文作者:oslh
    原文地址: https://segmentfault.com/a/1190000003053724
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞