5-1 事件机制
本节编程练习不计算学习进度,请电脑登录imooc.com操作

事件机制

jQuery对事件的绑定分别有几个API

.bind()/.live()/.delegate()/.on()

不管是用什么方式绑定,归根到底还是用addEventListener/attachEvent处理的,正如选择器一样不管如何匹配最终还是那么几个浏览器接口处理,既然如此,事件为什么还要区分那么多不同的处理方案?

这里就要涉及到 DOM 事件处理模型了,就是常提到的捕获与冒泡传统的事件处理给某一元素绑定了一个点击事件,传入一个回调句柄处理。

element.addEventListener('click',doSomething,false)

这样的代码再正常不过了,但是,如果页面上有几百个元素需要绑定(假设),那么务必就要绑定几百次啦。
这样问题就出现了:

第一:大量的事件绑定,性能消耗,而且还需要解绑(IE会泄漏)
第二:绑定的元素必须要存在
第三: 后期生成HTML会没有事件绑定,需要重新绑定
第四: 语法过于繁杂

有没有办法优化呢?答案是肯定的,那就是采用委托的机制

事件委托

DOM 有个事件流的特性,也就是说我们在页面上触发节点的时候事件都会上下或者向上传播,事件捕捉和事件冒泡。

DOM2.0 模型将事件处理流程分为三个阶段:

一、事件捕获阶段
二、事件目标阶段
三、事件起泡阶段


事件传送可以分为3个阶段。
(1)在事件捕捉(Capturing)阶段,事件将沿着DOM树向下转送,目标节点的每一个祖先节点,直至目标节点。例如,若用户单击了一个超链接,则该单击事件将从document节点转送到html元素,body元素以及包含该链接的p元素。在此过程中,浏览器都会检测针对该事件的捕捉事件监听器,并且运行这件事件监听器。
(2)在目标(target)阶段,浏览器在查找到已经指定给目标事件的事件监听器之后,就会运行该事件监听器。目标节点就是触发事件的 DOM 节点。例如,如果用户单击一个超链接,那么该链接就是目标节点(此时的目标节点实际上是超链接内的文本节点)。
(3)在冒泡(Bubbling)阶段,事件将沿着DOM树向上转送,再次逐个访问目标元素的祖先节点到document节点。该过程中的每一步。浏览器都将检测那些不是捕捉事件监听器的事件监听器,并执行它们。
利用事件传播(这里是冒泡)这个机制,就可以实现事件委托

具体来说,事件委托就是事件目标自身不处理事件,而是把处理任务委托给其父元素或者祖先元素,甚至根元素(document)

委托这么好的特性 jQuery 当然不会放过,所以就衍生出  .bind()、.live() .on()和.delegate(),jQuery 的事件绑定有多个方法可以调用,以 click 事件来举例:

click方法
bind方法
delegate方法
on方法

这里要清楚的认识:不管你用的是(click / bind / delegate)之中哪个方法,最终都是 jQuery 底层都是调用 on 方法来完成最终的事件绑定。因此从某种角度来讲除了在书写的方便程度及习惯上挑选,不如直接都采用 on 方法来的痛快和直接。

所以在新版的 API 中都这么写到:

.on()方法事件处理程序到当前选定的 jQuery 对象中的元素。在jQuery 1.7中,.on()方法提供绑定事件处理的所有功能、效果不言而喻了,除了性能的差异,通过委托的事件还能很友好的支持动态绑定,只要 on 的delegate 象是 HTML 页面原有的元素,由于是事件的触发是通过Javascript的事件冒泡机制来监测,所以对于所有子元素(包括后期通过JS生成的元素)所有的事件监测均能有效,且由于不用对多个元素进行事件绑定,能够有效的节省内存的损耗。

任务

  1. <!doctype html>
  2. <html>
  3. <head>
  4. <meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
  5. <script src="http://www.imooc.com/static/lib/jquery/1.9.1/jquery.js" type="text/javascript"></script>
  6. <style>
  7. div { width:60px; height:60px; margin:5px; float:left; }
  8. </style>
  9.  
  10. <title>事件委托</title>
  11. </head>
  12. <body>
  13.  
  14. <h2>事件绑定的2种方式</h2>
  15.  
  16. <ul id="resources">
  17. <li><a href="http://opera.com/wsc">Opera Web Standards Curriculum</a></li>
  18. <li><a href="http://sitepoint.com">Sitepoint</a></li>
  19. <li><a href="http://alistapart.com">A List Apart</a></li>
  20. <li><a href="http://yuiblog.com">YUI Blog</a></li>
  21. <li><a href="http://blameitonthevoices.com">Blame it on the voices</a></li>
  22. <li><a href="http://oddlyspecific.com">Oddly specific</a></li>
  23. </ul>
  24. <script type="text/javascript">
  25.  
  26. //常规写法
  27. (function() {
  28. var resources = document.getElementById('resources');
  29. var links = resources.getElementsByTagName('a');
  30. var all = links.length;
  31. for (var i = 0; i < all; i++) {
  32. //循环绑定
  33. links[i].addEventListener('click', handler, false);
  34.  
  35. };
  36. function handler(e) {
  37. var x = e.target;
  38. alert('addEventListener绑定: '+ x);
  39. e.preventDefault();
  40. };
  41. })();
  42.  
  43. //事件委托
  44. (function() {
  45. var resources = document.getElementById('resources');
  46. //绑定父元素
  47. resources.addEventListener('click', handler, false);
  48. function handler(e) {
  49. var x = e.target;
  50. if (x.nodeName.toLowerCase() === 'a') {
  51. alert('事件委托: ' + x);
  52. e.preventDefault();
  53. }
  54. };
  55. })();
  56.  
  57.  
  58.  
  59.  
  60. </script>
  61.  
  62. </body>
  63. </html>
下一节