06 Feb 2014
jQuery事件绑定bind,delegate,live,on比较
如果把一个Web页面比作人,HTML构建了骨架,CSS美化了外观,JavaScript则是让整个人鲜活起来的灵魂。而鲜活起来的基础则是:DOM对象的事件(event)和回调函数(event handler)进行绑定。jQuery 提供封装了很多方法来进行事件绑定:
但是为何 jQuery 提供了这四种方法,之间有何差异?我们在开发中,应该如何区别使用?即使点开上述四个链接,到官方文档中去查阅,也难免理解起来生涩。Linus Torvalds 曾经说过:
Talk is cheap, show me the code.
所以接下来就通过直观等价的代码来阐述下这几者之间的差异。
bind
$(selector).bind(eventType, handler);
等价于
$(selector).each(function() {
this.onEventType = handler;
});
jQuery 选择器对应的每个DOM元素,都直接进行了事件和回调函数的绑定。但是,在执行bind
时,这些元素必须是已经存在的了。比如
<p>
<button id="firstBtn">First</button>
</p>
$("p > button").bind("click", function() {
alert($(this).attr("id"));
});
// append another button
$('<button id="secondBtn">Second</button>').appendTo("p");
在上述代码中,先进行事件绑定,事件绑定时满足 p > button
选择器的只有 button#firstBtn
,因此只有该按钮会
响应点击事件。而后续新增的 button#secondBtn
虽然也满足 p > button
,但是在 bind
后,不会响应点击事件的。
delegate
$(selector).delegate(childSelector, eventType, handler);
等价于
$(selector).bind(eventType, function(event) {
if ($.inArray(event.target, $(this).find(childSelector))) {
handler.call(event.target, event);
}
});
如此做法,就灵活了很多,子DOM元素受触发的事件,都会冒泡到父元素,
调用绑定好的回调函数,检查event.target
是否是$(selector).find(childSelector)
,
如果满足,再执行handler
。因此,即使是在delegate
之后才创建的DOM元素,
只要DOM元素满足 $(selector).find(childSelector)
就依然会响应事件。
对于上面的例子,如果采用delegate
来做事件绑定的话,依然有效。
<p>
<button id="firstBtn">First</button>
</p>
$("p").delegate("button", "click", function() {
alert($(this).attr("id"));
});
// append another button
$('<button id="secondBtn">Second</button>').appendTo("p");
不论是在delegate
之前以前已经存在,还是在delegate
之后动态创建,
只要p
不变,且DOM元素满足 $("p").find("button")
,都会alert
其自身的id
。
live
$(selector).live(eventType, handler);
等价于
$(document).delegate(selector, eventType, handler);
代码简洁有效,就不多废话了。不过live
在从 jQuery 1.7 就不建议使用,从 jQuery 1.9 起被删除了。
on
针对上面的局面,jQuery 的开发者用 on
来统一事件绑定,bind
,delegate
,live
都由on
衍生而来,
因为可以说on
是个大杂烩,综合了上述几种方法。
以下代码摘自jQuery 1.7.1 codebase in GitHub。
// ... more code ...
bind: function( types, data, fn ) {
return this.on( types, null, data, fn );
},
unbind: function( types, fn ) {
return this.off( types, null, fn );
},
live: function( types, data, fn ) {
jQuery( this.context ).on( types, this.selector, data, fn );
return this;
},
die: function( types, fn ) {
jQuery( this.context ).off( types, this.selector || "**", fn );
return this;
},
delegate: function( selector, types, data, fn ) {
return this.on( types, selector, data, fn );
},
undelegate: function( selector, types, fn ) {
return arguments.length == 1 ?
this.off( selector, "**" ) :
this.off( types, selector, fn );
},
// ... more code ...
Resources && References: