首先,可视化一个 HMTL 文档的 DOM 树是很有帮助的。一个简单的 HTML 页面看起来就像是这个样子:
事件冒泡 ( 又称事件传播 ) : 当我们点击一个链接时,其触发了链接元素的单击事件,该事件则引发任何我们已绑定到该元素的单击事件上的函数的执行。 利用事件传播(这里是冒泡)这个机制,就可以实现事件委托。具体来说,事件委托就是事件目标自身不处理事件,而是把处理任务委托给其父元素或者祖先元素,甚至根元素(document ) 。
一个单击操作会触发 alert 函数的执行。 click 事件接着会向树的根方向传播,广播到父元素,然后接着是每个祖先元素,只要是它的某个后代元素上的单击事件被触发,事件就会传给它 ,在操纵 DOM 的语境中, document 是根节点。
现在我们再来说明 .bind() 、 .live() 和 .delegate() 的不同之处 :
.bind()
这是最简单的绑定方法了。 JQuery 扫描文档找出所有的 $(' a') 元素,并把 alert 函数绑定到每个元素的 click 事件上。 注:其隐含意思,.bind() 只能给调用它的时候已经存在的元素绑定事件,不能给未来新增的元素绑定事件 。如果是Ajax 过来的元素则无能为力,但是其胜在效率高
.live()
JQuery 把 alert 函数绑定到 $(document) 元素上,并使用 'click' 和 'a' 作为参数。任何时候只要有事件冒泡到 document 节点上,它就查看该事件是否是一个 click 事件,以及该事件的目标元素与 'a' 这一 CSS 选择器是否匹配,如果都是的话,则执行函数。 jQuery 从 1.4 开始支持在使用 .live() 方法时配合使用一个上下文参数:
.delegate()
JQuery 扫描文档查找 $('#container') ,并使用 click 事件和 'a' 这一 CSS 选择器作为参数把 alert 函数绑定到 $('#container') 上。任何时候只要有事件冒泡到 $('#container') 上,它就查看该事件是否是 click 事件,以及该事件的目标元素是否与 CSS 选择器相匹配。如果两种检查的结果都为真的话,它就执行函数。 (注:如果监听父控件被移除,其响应事件也会失效)可见,.delegate()方法是一个相对完美的解决方案。但在DOM结构简单的情况下,也可以使用.live()。
1、 这句话是否正确?
如上面的代码,后者实际上要快过前者,因为前者首先要扫描整个的文档查找所有的 $(‘a') 元素,把它们存成 jQuery 对象。尽管 live 函数仅需要把 'a' 作为串参数传递以用做之后的判断,但是 $() 函数并未 “ 知道 ” 被链接的方法将会是 .live() 。而另一方面, delegate 方法仅需要查找并存储 $(document) 元素。 一种解决的办法为,使用一种“早委托”的方式,如下:
在此,(function($){ … })(jQuery) 是一个“立即执行的匿名函数”,构成了一个闭包,可以防止命名冲突。在匿名函数内部, $ 参数引用 jQuery 对象。这个匿名函数不会等到 DOM 就绪就会执行。 注意,使用这个hack 时,脚本必须是在页面的 head 元素中执行的 ,意味着在 $(document).reday()之外执行 。之所以选择这个时机,因为这时候刚好document 元素可用,而整个 DOM 还远未生成;如果把脚本放在结束的 body 标签前面,就没有意义了,因为那时候 DOM 已经完全可用了。
2、.live() 相比 .delegate() 缺点有哪些?
一、$() 函数会找到当前页面中选择器匹配元素并创建 jQuery 对象,但在确认事件目标时却不用这个元素集合,而是使用选择符表达式与 event.target 或其祖先元素进行比较,因而生成这个 jQuery 对象会造成不必要的开销;
二、默认把事件绑定到$(document) 元素,如果 DOM 嵌套结构很深,事件冒泡通过大量祖先元素会导致性能损失;
三、只能放在直接选择的元素后面,不能在连缀的DOM 遍历方法后面使用,即 $( “ #infotable td ” ).live …可以,但 $(“#infotable ” ).find( “ td ” ).live …不行;
四、收集选择器匹配元素并创建jQuery 对象,但实际操作的却是 $(document) 对象,令人费解。
3、.live() 真的绑定在 document 上面吗?
可以绝对的肯定。写一个样例,html 代码为:
测试代码:
其测试结果为: ccc > aaa > bbb,和预期相符合