事件委托
什么是事件委托?用现实中的理解就是:有100个学生同时在某天中午收到快递,但这100个学生不可能同时站在学校门口等,那么都会委托门卫去收取,然后再逐个交给学生。而在jQuery中,我们通过事件冒泡的特性,让子元素绑定的事件冒泡到父元素(或祖先元素)上,然后再进行相关处理即可。
如果一个企业级应用做报表处理,表格有2000行,每一行都有一个按钮处理。如果用之前的.bind()处理,那么就需要绑定2000个事件,就好比2000个学生同时站在学校门口等
快递,不但会堵塞路口,还会发生各种意外。这种情况放到页面上也是一样,可能导致页面极度变慢或直接异常。而且2000个按钮使用ajax分页的话,.bind()方法无法动态绑定尚
未存在的元素。就好比,新转学的学生,快递员无法验证他的身份,就可能收不到快递。
有html代码如下:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>高级事件</title> <script type="text/javascript" src="jquery-1.12.3.js"></script> <script type="text/javascript" src="jquery-migrate-1.2.1.js"></script> <script type="text/javascript" src="demo.js"></script> <link rel="stylesheet" type="text/css" href="style.css" /> </head> <body> <div style=" 200px; height: 200px; background: green;" id="box"> <input type="button" class="button" value="按钮" /> </div> </body> </html>
使用.bind()绑定一个事件:
$(".button").bind("click", function() { alert("事件不委托!"); });
也可使用.live()绑定一个事件:
$(".button").live("click", function() { alert("事件委托!"); });
但要注意:使用live绑定的是document,而非button,所以永远只会绑定一次事件!
使用.bind()不具备动态绑定功能,只有点击原始按钮才能生成:
//bind无法动态绑定事件 $(".button").bind("click", function() { $(this).clone().appendTo("#box"); });
使用.live()具备动态绑定功能,jQuery1.3使用,jQuery1.7之后废弃,jQuery1.9删除,所以还需引入向下兼容插件——jquery-migrate-1.2.1.js
//live可以动态绑定事件,因为事件绑定在document上 $(".button").live("click", function() { $(this).clone().appendTo("#box"); });
.live()原理就是把click事件绑定到祖先元素$(document)上,而只需要给$(document)绑定一次即可,而非2000次,然后就可以处理后续动态加载的按钮的单击事件。在接受任何事件时,$(document)对象都会检查事件类型(event.type)和事件目标(event.target),如果click事件是.button,那么就执行委托给它的处理程序,.live()方法已经被删除,无法使用了,需要测试使用的话,需要引入向下兼容插件。
一句话总结:live绑定在document上,而点击button其实是冒泡到document上,并且点击document时候,需要验证event.type和event.target才能触发。
.live()无法使用链接连缀调用,因为参数的特性导致。即下列代码无效:
//live是不支持元素连缀调用的 $("#box").children(0).live("click", function() { $(this).clone().appendTo("#box"); });
在上面的例子中,我们使用了.clone()克隆。其实如果想把事件行为复制过来,我们只需要传递true即可:.clone(true),这样也能实现类似事件委托的功能,但原理却截然不同,一个是复制事件行为,一个是事件委托,而在非克隆操作下,此类功能只能使用事件委托。
$(".button").bind("click", function() { $(this).clone(true).appendTo("#box"); //其实是复制事件行为 });
在非克隆操作下,此类功能只能使用事件委托:
$(".button").live("click", function() { $('<input type="button" class="button" value="按钮" />').appendTo("#box"); });
或
$(".button").live("click", function() { $('<input type="button" class="button" value="按钮" />').clone(true).appendTo("#box"); });
又或
$(".button").live("click", function() { $('<input type="button" class="button" value="按钮" />').clone().appendTo("#box"); });
如果使用.bind()复制事件行为,则无法动态绑定:
$(".button").bind("click", function() { $('<input type="button" class="button" value="按钮" />').clone(true).appendTo("#box"); });
当我们需要停止事件委托的时候,可以使用.die()来取消掉。
$(".button").live("click", function() { $(this).clone().appendTo("#box"); }); $(".button").die("click"); //和unbind一个意思
由于.live()和.die()在jQuery1.4.3版本中废弃了,之后推出语义清晰、 减少冒泡传播层次、又支持链接连缀调用方式的方法:.delegate()和.undelegate(),但这个方法在 jQuery1.7版本中被.on()方法整合替代了。
$("#box").delegate(".button", "click", function() { $(this).clone().appendTo("#box"); }); $("#box").undelegate(".button", "click");
live的替代方法delegate(),live语义不清晰,由于它没有指定绑定谁,所以不清晰;而delegate语义清晰,绑定谁,谁就在开头。
支持连缀调用方式:
$("div").first().delegate(".button", "click", function() { $(this).clone().appendTo("div:first"); });
注意:.delegate()需要指定父元素,然后第一个参数是当前元素,第二个参数是事件方式,第三个参数是执行函数。和.bind()方法一样,可以传递额外参数,.undelegate()和.unbind()方法一样可以直接删除所有事件,比如:.undelegate('click'),也可以删除命名空间的事件,比如:.undelegate('click.abc')。
注意:.live()和.delegate()和.bind()方法一样都是事件绑定,那么区别也很明显,用途上遵循两个规则:
- 在DOM中很多元素绑定相同事件时
- 在DOM中尚不存在即将生成的元素绑定事件时。
我们推荐使用事件委托的绑定方式,否则推荐使用.bind()的普通绑定。
on、off和one
目前绑定事件和解绑的方法有三组共六个。由于这三组的共存可能会造成一定的混乱,为此jQuery1.7以后推出了.on()和.off()方法彻底摒弃前面三组。
html代码如下:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>高级事件</title> <script type="text/javascript" src="jquery-1.12.3.js"></script> <script type="text/javascript" src="jquery-migrate-1.2.1.js"></script> <script type="text/javascript" src="demo.js"></script> <link rel="stylesheet" type="text/css" href="style.css" /> </head> <body> <div style=" 200px; height: 200px; background: green;" id="box"> <input type="button" class="button" value="按钮" /> </div> </body> </html>
替代.bind()方式:
$(".button").on("click", function() { alert("替代bind"); });
替代.bind()方式,并使用额外数据和事件对象:
$(".button").on("click", {user:'Lee'}, function(e) { alert("替代bind" + e.data.user); });
替代.bind()方式,并绑定多个事件:
$(".button").on("mouseover mouseout", function(e) { alert("移入移出"); });
替代.bind()方式,以对象模式绑定多个事件:
$(".button").on({ mouseover:function() { alert("移入"); }, mouseout:function() { alert("移出"); } });
又html代码如下:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>高级事件</title> <script type="text/javascript" src="jquery-1.12.3.js"></script> <script type="text/javascript" src="jquery-migrate-1.2.1.js"></script> <script type="text/javascript" src="demo.js"></script> <link rel="stylesheet" type="text/css" href="style.css" /> </head> <body> <form action="123.html"> <div style=" 200px; height: 200px; background: green;" id="box"> <input type="submit" class="button" value="按钮" /> </div> </form> </body> </html>
替代.bind()方式,阻止默认行为并取消冒泡:
$("form").on("submit", function() { return false; });
或
$("form").on("submit", false);
替代.bind()方式,阻止默认行为:
$('form').on('submit', function (e) { e.preventDefault(); });
替代.bind()方式,取消冒泡:
$('form').on('submit', function (e) { e.stopPropagation(); });
替代.unbind()方式,移除事件:
$(".button").on("click", function() { alert("替代bind"); }); $(".button").off("click");
替代.live()和.delegate(),事件委托:
$("#box").on("click",".button",function() { $(this).clone().appendTo("#box"); });
替代.die()和.undelegate(),取消事件委托:
//替代.live .delegate $("#box").on("click",".button",function() { $(this).clone().appendTo("#box"); }); //移除事件委托 $("#box").off("click",".button");
注意:和之前方式一样,事件委托和取消事件委托也有各种搭配方式,比如额外数据、命名空间等等,这里不在赘述。
不管是.bind()还是.on(),绑定事件后都不是自动移除事件的,需要通过.unbind()和.off()来手工移除。jQuery 提供了.one()方法,绑定元素执行完毕后自动移除事件,one()方法仅触发一次事件。
类似于.bind()只触发一次:
//仅一次事件触发 $(".button").one("click", function() { alert("仅一次事件触发"); });
类似于.delegate()只触发一次:
$("#box").one("click",".button",function() { $(this).clone().appendTo("#box"); });