你尚未登录,仅允许查看本站部分内容。请登录使用邀请码注册
二哲|风变科技

可想造一个属于你自己的jQuery库?(九,实现on&off) 2个回复 专栏 @ 框架与库

二哲|风变科技 发布于 2 年前

Lesson-9


上一篇在div.io已经发过了如何实现事件委托传送门:http://div.io/topic/1357

这篇我们直接进入事件部分。

关于事件部分,我思考了很久,也参考了许多,到底如何能用一个很简单的方法实现一模一样的on、off呢?

最后我的设计思路是:

1.有一个全局存储所有Events的数组,存放每个dom元素上的事件。

2.给每个DOM一个guid的唯一标识符,通过这个guid来找出Events数组里的事件。

由于逻辑比较复杂,我们先来画个图看看。

事件设计流程图

首先,我们利用DOM可以增加自定义属性的原理,在它的身上存一个guid。

之后整个事件机制就根据这个guid来进行查找与存储。

接下来是代码部分

Kodo.Events = []; //事件绑定存放的事件
Kodo.guid = 0; //事件绑定的唯一标识

on: function(type, selector, fn) {
    if (typeof selector == 'function') {
    fn = selector; //两个参数的情况
    for (var i = 0; i < this.length; i++) {
    if (!this[i].guid) {
    this[i].guid = ++Kodo.guid;
    //guid 不存在,给当前dom一个guid

    Kodo.Events[Kodo.guid] = {};
                /*
                *给Events[guid] 开辟一个新对象
                *用于存储这个dom上的所有事件方法
                */

    Kodo.Events[Kodo.guid][type] = [fn]; //每个方法都是一个数组
    //给这个新对象,赋予事件数组 "click" : [fn1,fn2,...]

    bind(this[i], type, this[i].guid);//绑定事件

    } else {//guid存在的情况
    var id = this[i].guid;
    if (Kodo.Events[id][type]) {
    //如果这存在是当前事件已经存过,不用在绑定事件,直接放入方法数组即可
    Kodo.Events[id][type].push(fn);
    } else {
    //这是存新事件,所以需要重新绑定一次
    Kodo.Events[id][type] = [fn];
    bind(this[i], type, id);
    }
    }
    }
    }
}

function bind(dom, type, guid) {
dom.addEventListener(type, function(e) { //绑定相应事件
for (var i = 0; i < Kodo.Events[guid][type].length; i++) {
    //循环执行那个方法数组即可
Kodo.Events[guid][type][i].call(dom, e); //正确的dom回调
}
}, false);
}

由于方法过长,我就把讲解的都写在了代码里,这样看的也会更方便一些。

代码还是不够形象!我们来看看log就能更清晰明白其中的奥秘。

通过控制台log出f.Events 发现正是我们想要的结果,每个dom对应一个自己的evtObj, 通过Kodo.Events[guid] 可以得到指定的evtObj。然后即可取出自己相应的事件。

绑定事件demo

如果我继续新增事件

绑定事件demo1

可以发现,我只针对于第一个li增加了事件。log出Evnets也就只有第一个Object有新增,并且会增加到对应的事件数组里。

理解了这个后要解除事件绑定,那就非常简单了。同样根据guid查找到对应的方法数组,delete即可

off: function(type, selector) {
if (arguments.length == 0) {
//如果没传参数,清空所有事件
for (var i = 0; i < this.length; i++) {
var id = this[i].guid;
for (var j in Kodo.Events[id]) {
delete Kodo.Events[id][j];
}
}
} else if (arguments.length == 1) {
//指定一个参数,则清空对应type的事件
for (var i = 0; i < this.length; i++) {
var id = this[i].guid;
delete Kodo.Events[id][type];
}
} 
}

一个没有带有事件委托的on、off就可以这样实现了。

那如果我们要实现带委托的怎么办呢?

我们可以用这同样的思路实现,只是要多进行一个指定selector的存储。

这个我们就放在下一课最后讲解。

star是尊重作者知识果实最好的回报 :)

github地址: https://github.com/MeCKodo/forchange/tree/master/lesson-9
可想自己造一个jQuery库?(八):http://div.io/topic/1467

版权声明:自由转载-非商用-非衍生-保持署名

登录后回复,如无账号,请使用邀请码注册