简言
jQuery事件处理随着时间的推移一直在不断的发展,新手朋友有一些可能跟俺一样对事件的绑定为什么有那么多方法有一些疑惑。
今天俺就跟大家一起来学习jQuery事件绑定中bind,live,delegate,和on之间的区别。
Javascript是事件驱动类型的语言,毫不夸张的说事件几乎是所有web应用的核心。事件大致可以分为浏览器事件,表单事件,鼠标事件和键盘事件。有的时候你绑定了事件,但你可能没有意识到。如ready()事件处理方法,基于浏览器事件。绑定到事件的函数或方法称为事件处理程序:
$(document).ready(function () { // 业务逻辑代码 });
随着jQuery的发展,旧版本jQuery中的bind方法,live方法和delegate方法,在1.7之后都被on取代了。今天俺就跟大家一起来学习看看为什么要引入on方法,bind方法,live方法和delegate方法有什么缺陷呢?
jQuery bind方法
大家思考一下以下代码:
<div id="container"> <a href="#">Go to XYZ</a> <a href="#">Go to ABC</a> <a href="#">Go to MNC</a> <a href="#">Go to TUV</a> </div>
当你调用bind()时,你将一个事件处理程序附加到选择中的每个匹配元素,在我们的例子中是div’container’中的每个锚元素。
你也可以使用click()编写相同的代码,click()是编写bind()的简写方法。
$(function () { $("#container a").bind("click", function () { console.log("clicked"); }); });
但是,通过使用bind()版本,您可以为多个事件分配一个处理程序。 bind()还支持命名空间事件(http://api.jquery.com/on/#event-names)
当您单击链接时,请在每次单击锚元素时观察控制台中的单击计数增加。但是,如果’container’div中有100个锚点,bind()方法会将事件处理程序附加到所有100个锚点!类似地想象一个大表,其中每一行都有一个锚元素,所有这些都需要一个点击处理程序。在这里使用bind()可能会导致性能问题;如果要反复附加事件处理程序,尤其是在处理大量选择时。
bind()方法的另一个问题是,由于它直接将事件处理程序绑定到单个元素,因此它无法将这些处理程序绑定到在运行时动态创建的元素。
因此,使用相同的示例,如果我们要动态地将一个锚元素添加到div’容器’并单击它,会发生什么?让我们看一个例子。在相同的代码中,我使用clone()方法克隆锚元素并在运行时将其添加到’container’div中。
$("#container a").bind("click", function () { console.log("clicked"); $(this).clone().appendTo("#container"); });
每次单击锚点时,“控制台”窗口中单击的消息计数都会增加。 但是现在尝试单击这些动态创建的锚点。 你会看到计数没有增加。 这是因为锚点不响应click事件,就像使用bind()时一样; 您的事件处理函数与您添加到DOM的任何新元素都没有关联。
使用unbind()删除使用bind()创建的事件绑定。
jQuery live方法
live()是在jQuery 1.3中引入的,其语法类似于bind()。 您所要做的就是用live()替换bind(),将处理程序绑定到所有当前和未来匹配元素的事件。
$(function () { $("#container a").live("click", function () { console.log("clicked"); }); });
live()实现事件委托。绑定到live()的处理程序没有绑定到锚元素,因为它可能会出现。相反,live()将处理程序绑定到DOM的根目录。因此,不是将100个事件处理程序附加到“容器”div中的所有锚元素,而是使用live()将一个事件处理程序连接到根文档,以及关联的选择器(在我们的示例中为#container a)和事件信息。
当我们单击一个锚元素时,会生成一个click事件并传递给<div>。由于处理程序未绑定到<div>,因此事件冒泡到DOM级别,jQuery使用event.target检查它是否与选择器表达式匹配;在这种情况下,#container a。然后,它使用点击源的上下文执行事件。
总结一下,live()方法告诉浏览器观察文档中任何位置的所有点击。如果单击的元素与#container选择器匹配,则执行处理程序。这意味着你有一个事件处理程序而不是100个,这意味着它在浏览器上更快更容易。
- live()方法的最大缺点是在执行处理函数之前,事件必须一直传播到根文档。 在大型DOM树中,这可能再次导致性能问题。
- event.StopPropagation无法阻止文档中较低的事件处理程序冒泡DOM树,因为事件已经传播到根目录。
- jQuery使用选择器来检索元素,这在大型DOM中可能非常耗时。 然后它在文档上注册事件处理程序后丢弃了选择器,这又是一种浪费。
- live()在链式调用支持方面也受到限制。 例如,你不能做$(‘#container’).find(‘.something’).live()
jQuery delegate方法
克服live()中的这些瓶颈; 在jQuery 1.4.2中引入了delegate()。 delegate()在内部使用了live(),并且可以作用于动态创建的元素。 我们来看看语法:
$('#container').delegate('selector','event',function() { });
我们可以把上面的代码改写成这样代码:
$("#container").delegate('a', 'click', function () { console.log("clicked"); $(this).clone().appendTo("#container"); });
delegate允许您指定事件侦听器在文档中的位置。通过这样做,事件不必在调用处理程序函数之前一直到达根文档。相反,它将事件处理程序与选择器和事件信息一起附加到div“container”。你可以在这里看到delegate()函数http://jsfiddle.net/jqueryhowto/hbSKw/3/
在上面的代码中,首先选择一个元素(#container),其中包含要将事件添加到的元素。这与您在使用bind()时所做的不同,您在其中直接选择了要添加事件的元素。接下来,调用delegate()函数并传递选择器,事件名称以及处理事件时执行的函数。
live()和delegate()之间的主要区别在于live()不支持DOM遍历,而委托支持将事件绑定到特定DOM元素。
使用undelegate()删除使用delegate()创建的事件绑定。
jQuery on方法
在你可以看到,有很多方法,都集中在一般事件绑定上。 在jQuery 1.7中,引入了on()方法,该方法旨在将大多数事件绑定函数简化并合并为一个统一的一致API。 如果您有兴趣了解on()如何替换所有这些事件方法的功能,请打开jQuery 1.7.1源代码(https://github.com/jquery/jquery/blob/1.7/src/event.js#L965)你会发现bind(),live()和delegate()都指向on()方法。
我们来看看on的语法:
$('#container').on('events', 'selector', 'data' ,function() { });
我们可以把之前的代码改写成这样:
$("#container").on('click', 'a', function () { console.log("clicked"); $(this).clone().appendTo("#container"); });
将on()视为一种更简化的附加事件处理程序的方式。 对于所有版本的jQuery 1.7及更高版本,你应该使用on()。 另请注意,click()是on()的快捷方式。当您使用仅由on()支持的事件委托语法时,on()和click()之间的区别很明显。 另一个区别是on()支持多个事件,如.on(‘keyup click doubleclick’)。
让我们快速回顾一下bind(),live()和delegate()的语法,以及如何将代码转换为支持on:
// Using bind() $("#container a").bind("click", function () {}); // Using on() $("#container a").on("click", function () { }); live() and on() // Using live() $("#container a").live("click", function () {}); // Using on() $("#container").on("click", "a", function () { }); delegate() and on() // Using delegate() $("#container").delegate('a', 'click', function () {}); // Using on() $("#container").on("click", "a", function () { });