前言:看两三遍就好了。在查看jQuery源代码时,我发现了这条评论://Sourcecode5235lines/**Helperfunctionsformanagingevents--notpartofthepublicinterface。*支持DeanEdwards的addEvent库的许多想法。*/jQuery.event={}DeanEdwards的addEvent.js库为jQuery的事件绑定提供了很多思路,我们来看看2005年的addEvent.js。〇.先回顾一下Object的内存地址指向的知识leta={}letb=ab[0]='111'console.log(a,'a55')//{0:'111'}b改变属性,a也会改变,因为b和a指向同一个地址(b=a)1.AddEvent()函数:为目标元素绑定事件(比如点击)源代码://addEvent为DOM元素绑定事件//用于创建唯一ID的计数器//为每个事件添加一个唯一IDaddEvent.guid=1;functionaddEvent(element,type,handler){//为每个事件处理程序分配一个唯一的ID//如果用户自定义回调函数如果没有$$guid,//为每个处理程序添加一个唯一的idif(!handler.$$guid)handler.$$guid=addEvent.guid++;//为元素创建事件类型的哈希表//for将事件属性添加到目标元素if(!element.events)element.events={};//为每个元素/事件对创建事件处理程序的哈希表//events是绑定到目标元素的事件集合//first第一次使用addEvent绑定通常是未定义的lethandlers=element.events[type];如果(!handlers){handlers=element.events[type]={};//存储现有的事件处理程序(如果有)//handlers的0属性用作目标元素的本机绑定事件if(element["on"+type]){handlers[0]=元素["on"+类型];}}//将事件处理程序存储在哈希表中//将每个绑定事件保存到处理程序的id属性handlers[handler.$$guid]=handler;//分配一个全局事件处理程序来完成所有工作//为目标元素的本机事件绑定一个处理程序(handleEvent)element["on"+type]=handleEvent;}分析:注意让handlers=element.events[type],handlers和element.events[type]指向同一个地址,下一步就是对handlers进行操作,其实关键是对element.events进行操作!addEvent的目的是让目标元素的结构如下:element:{//依次执行click对象中的各个handleronclick:handleEvent(MouseEvent)events:{click:{//如果先onclick,就会//0:onclick(即function(e){console.log('clickedone')})1:handler(即function(){console.log('clickedone')})2:handler(xxx)3:.....:...},focus:{},.....:{}}}注意里面的注释(1)可以看出,addEvent绑定的'click'事件并不是真正绑定到元素上,而是绑定的事件处理器(handler)放在了元素的事件上,即绑定事件和事件的分离targetelements(2)点击事件由handleEvent统一执行2.handleEvent()的作用:executeeventhandler源码://executeeventhandlerfunctionhandleEvent(event){//抓取事件对象(IE用的是全局的eventobject)console.log(event,'event55')//event为MouseEvent,原生鼠标事件集合event=event||窗口事件;//获取事件处理者哈希表的引用//查找同一事件的处理者//注意this引用目标元素//查找处理者集合lethandlers=this.events[event.type];//执行每个事件处理器//依次执行事件处理器for(letiinhandlers){this.$$handleEvent=handlers[i];这个。$$handleEvent(事件);}}分析:(1)看到上面的key,再看handleEvent就简单多了,就是把element->events->click中的所有事件处理程序都执行(2)主要看for,有比较多的是handlers和handleEvent,我觉得是多余的(不知道下面说的对不对,因为中学的时候想到了解数学题,当你觉得不能用题干里的条件的时候,你经常想错了),因为直接这样写就可以了:写法一:functionhandleEvent(event){event=event||窗口事件;因为(让我inthis.events[event.type]){this.events[event.type][i](event)}}写法二:functionhandleEvent(event){event=event||窗口事件;让处理程序=这个。事件[事件类型];for(letiinhandlers){handlers[i].call(this,event)}}根据谁调用了this,this就是谁的原则,那么handleEvent的this就是element["on"+type],即,element.onclick是在调用handleEvent方法。既然调用的是element的属性onclick,那么执行上下文就是element,this就是element。DeanEdwards使用this.$$handleEvent来执行handler,目的是为了保证Scope的正确性,即this3.removeEvent//移除监听事件函数removeEvent(element,type,handler){//从中删除事件处理器哈希表console.log(handler,'handler52')if(element.events&&element.events[type]){deleteelement.events[type][handler.$$guid];}}注意:如果不将自定义事件包装成变量,则无法移除监听事件:letone=document.querySelector("#one")addEvent(one,'click',function(){console.log('clickedone')})removeEvent(one,'click',function(){console.log('clickedone')})可以这样写:让一个=document.querySelector("#one")lethandler=function(){console.log('clickedone')}addEvent(one,'click',handler)removeEvent(one,'click',handler)4.实验
