微信号:FrontDev

介绍:分享 Web 前端相关的技术文章、工具资源、精选课程、热点资讯

前端事件系统(二)

2015-10-15 19:51 前端大全

(点击上方,可快速关注)


作者:observernote

网址:http://www.cnblogs.com/observernotes/p/4832011.html


本章将把重点放在于对于事件的委托机制,以及jquery的事件绑定方法做一些解析。本章并没有什么比较难懂的地方,也还没有深入到jQuery的事件系统内部。


事件委托


上一章讲了前端事件系统以及简单地对各个浏览器进行兼容的方法。对于要求不高的页面来说,之前的简单事件注册,就可以很好的胜任各种各样的工作了。但是,试想一种情况。倘若一个页面有着极大量的事件绑定的需求,那么我们之前的事件系统,就不得不一个个的去绑定事件。这样对性能来说,肯定是一种灾难,同时,动态增加的节点无法完成绑定的工作。因此,我们需要引入事件委托这一机制。


冒泡与捕获


我们知道dom的事件处理,分为捕获阶段,目标阶段,以及冒泡阶段三个部分。那么简单地讲一下这三个阶段吧,当我们点击了一个a标签的时候,整个事件的流程大致是下面的阶段


首先事件从dom树向下传送,逐个访问目标节点的祖先节点,同时将会对该事件的捕获事件监听器来进行检测,并执行,直到访问到目标节点,这一阶段就是我们说的捕获阶段;到达目标节点(即a标签)后,就会执行该事件监听器,这一阶段也就是目标节点;最后事件将会从目标节点开始,从dom树往上传送,再依次访问目标节点的祖先节点,并且执行对应的非捕获事件的事件监听器,并且执行


委托的原理


既然有了冒泡和捕获的概念,那么事件委托的原理也很好理解了。事件委托利用了事件可以传播的这一特性,并不使用事件本身对于事件来进行处理,而是将对事件的处理任务交予了其祖先节点来进行处理。


这样做,减少了对于页面上的dom操作。比如你对ul下的li绑定事件,通过事件委托,你只需要对于ul绑定一次事件,然后使用事件传播的这一特性,li的事件来进行工作,这样,极大地减少了绑定量,而且即使是动态增加的li节点,也同样是可以去执行该事件的。


jQuery的事件绑定


那么终于来到了jQuery的部分。从这里开始也将对jQuery的事件部分,尽个人所能来做一个解析,之后出现jQuery的源码的版本为2.1.4,解析过程中有不对的地方,欢迎打脸。


jQuery的事件绑定,有以下几种方法:


  • 直接用click,blur等事件名的方法

  • bind方法

  • delegate

  • live方法

  • one方法

  • on方法


那么我们对上面几种方法来一一分析(本章暂不会对作为核心的on的源码来进行分析)


  1. 直接用事件名进行事件绑定



即是直接采用类似.click(),.blur()的方式进行绑定

那么jQuery中是如何做到的呢


jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +

"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +

"change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) {


// Handle event binding

jQuery.fn[ name ] = function( data, fn ) {

return arguments.length > 0 ?

this.on( name, null, data, fn ) :

this.trigger( name );

};

});


jQuery的实现很简单,将事件直接通过each方法加入jQuery.fn上,然后在内部根据参数的不同直接对于jQuery的on或者trigger方法进行调用。


2.bind方法


bind方法用于为一个元素绑定一个事件处理程序

先来看看jQuery中的实现吧


bind: function( types, data, fn ) {

return this.on( types, null, data, fn );

}


3. live方法

live方法拿到前面来说。这是jQuery现在已经不支持的方法。对于1.4.3以上的版本,推荐采delgate方法来,而对于1.7以上的版本,则推荐采用on方法来进行替代。具体采用live方法有什么弊端,jQuery的文档之中已经阐述的非常明白了,至于为什么会出现这个问题,本着刻苦求知的精神……我还并没有去看,附上翻译后的文档吧


因为更高版本的jQuery提供了更好的方法,没有.live()方法的缺点,所以.live()方法不再推荐使用。特别是,使用.live()出现的以下问题:


  • 在调用 .live() 方法之前,jQuery 会先获取与指定的选择器匹配的元素,这一点对于大型文档来说是很花费时间的。

  • 不支持链式写法。例如,$("a").find(".offsite, .external").live( ... ); 这样的写法是不合法的,并不能像期待的那样起作用。

  • 由于所有的 .live() 事件被添加到 document 元素上,所以在事件被处理之前,可能会通过最长最慢的那条路径之后才能被触发。

  • 在移动 iOS (iPhone, iPad 和 iPod Touch) 上,对于大多数元素而言,click 事件不会冒泡到文档 body 上,并且如果不满足如下情况之一,就不能和 .live() 方法一起使用:

    • 使用原生的可被点击的元素,例如, a 或 button,因为这两个元素可以冒泡到 document。

    • 在 document.body 内的元素使用 .on() 或 .delegate() 进行绑定,因为移动 iOS 只有在 body 内才能进行冒泡。

    • 需要 click 冒泡到元素上才能应用的 CSS 样式 cursor:pointer (或者是父元素包含 document.documentElement)。但是依需注意的是,这样会禁止元素上的复制/粘贴功能,并且当点击元素时,会导致该元素被高亮显示。

  • 在事件处理中调用 event.stopPropagation() 来阻止事件处理被添加到 document 之后的节点中,是效率很低的。因为事件已经被传播到 document 上。

  • .live() 方法与其它事件方法的相互影响是会令人感到惊讶的。例如,$(document).unbind("click") 会移除所有通过 .live() 添加的 click 事件!


4. delegate方法


delegate方法也就是我们之前所提到的事件委托了。因为基于live之前的很多问题,jQuery在live之后的版本中增加了delgate方法(如今已经被on所取代)来看看现在的delegate是如何实现的吧


delegate: function( selector, types, data, fn ) {

return this.on( types, selector, data, fn );

}


5. one方法


为元素添加事件。并且在元素上的事件只可以执行一次


具体实现


one: function( types, selector, data, fn ) {

return this.on( types, selector, data, fn, 1 );

}


6. on方法


on方法在这里不打算对源码进行阅读,因为可以看到,上面的所有方法都是对于on方法的调用。因此jQuery的事件系统,核心就在于on方法了。因此jQuery的on方法将在后面进行分析,而这里,只是对于on接口本身的一些说明。


on方法提供了绑定事件所有的功能。其API是这样的


.on( events [, selector ] [, data ], handler(eventObject) )


其实最后还有一个one参数,倘若传入了1,那么这个事件也就只执行一次,而实现的原理其实也就是使用off来解绑事件进行的操作了。


然后来看下别的参数分别是做些什么的吧


events:

类型: String

一个或多个空格分隔的事件类型和可选的命名空间,或仅仅是命名空间,比如"click", "keydown.myPlugin", 或者 ".myPlugin"

selector:

类型: String

一个选择器字符串,用于过滤出被选中的元素中能触发事件的后代元素。如果选择器是 null 或者忽略了该选择器,那么被选中的元素总是能触发事件。

data:

类型: Anything

当一个事件被触发时,要传递给事件处理函数的event.data

handler(eventObject)

类型: Function()

事件被触发时,执行的函数。若该函数只是要执行return false的话,那么该参数位置可以直接简写成 false


因此再来对于前面五种方法来进行统一的分析。


直接用事件名进行事件绑定的方法与bind的方法,直接对于selector参数赋值为了null,因此,对于采用这两种方法进行的事件绑定,其实本身是没有使用事件委托的,即是说并没有冒泡的过程,因此,采用这种方法的绑定对性能会有一定的损耗。而delegate方法,传入了selector参数,因此,相当于也就是直接用on来实现的事件委托。one方法之前也讲了,所以不再多说。


总结一下这章所讲的内容吧。本章对于事件绑定的几种方法(除on外),都进行了简单地讲解。与其说是对于jQuery源码的分析,倒不如说其实就是个简单地,对于jQuery使用的建议吧。jQuery绑定的核心还是落在on方法上,同时,jQuery的事件系统的思想可以说是极为经典的。在下一章,我们将对jQuery的事件系统进行更深入一些的分析(在我捉急的水平范围之内)。第三章估计要难产了,我一定会努力做完这个系列的,也算是对个人前端学习的一点鞭策吧。




前端大全

微信号:FrontDev

打造东半球最好的 前端技术 微信号

--------------------------------------

商务合作QQ:2302462408

投稿网址:top.jobbole.com

 
前端大全 更多文章 5个典型的JavaScript面试题(上) Limu:JavaScript的那些书 Web开发:我希望得到的编程学习路线图 JavaScript基础工具清单 常用排序算法之JavaScript实现
猜您喜欢 福利贴 | Weex:JS & Web能力拓展万物互联的探索 证明你是坏程序员的7个迹象 最近碰到的三个Case 使用.NET开发Storm拓扑(文章合集) 一位电商数据分析师的经验总结