当我第一次学习jQuery时,通常会附加如下事件:
$('.my-widget a').click(function() { $(this).toggleClass('active'); });
在学习了更多关于选择器速度和事件委托的知识之后,我在几个地方读到“ jQuery事件委托将使您的代码更快。” 所以我开始写这样的代码:
$('.my-widget').on('click','a',function() { $(this).toggleClass('active'); });
这也是复制已过时的.live()事件的行为的推荐方法。这对我来说很重要,因为我的许多站点始终都在动态添加/删除小部件。上面的行为与.live()并不完全一样,因为只有添加到已经存在的容器’.my- widget’中的元素才会获得该行为。如果在代码运行后我动态添加了另一个html块,则这些元素将不会获得绑定到它们的事件。像这样:
setTimeout(function() { $('body').append('<div class="my-widget"><a>Click does nothing</a></div>'); }, 1000);
我现在附加所有这样的事件:
$(document).on('click.my-widget-namespace', '.my-widget a', function() { $(this).toggleClass('active'); });
这似乎可以满足我的所有目标。(是的,由于某种原因,它在IE中的运行速度较慢,不知道为什么吗?)之所以快,是因为只有单个事件绑定到单个元素,并且仅在事件发生时才评估辅助选择器(如果此处有误,请更正我)。命名空间很棒,因为它使切换事件侦听器更加容易。
因此,我开始认为jQuery事件应始终绑定到$(document)。 有什么理由为什么您不想这样做? 可以认为这是最佳做法吗?如果没有,为什么?
如果您已经阅读了整本书,那么谢谢。我感谢任何/所有反馈/见解。
假设:
.on()
否-不应将所有委托的事件处理程序绑定到该document对象。这可能是您可能创建的性能最差的方案。
document
首先,事件委托并不能总是使您的代码更快。在某些情况下,这是有利的,而在某些情况下则不是。当您实际需要事件委托并从中受益时,应该使用事件委托。否则,您应该将事件处理程序直接绑定到事件发生的对象,因为这样通常会更有效。
其次,您不应在文档级别绑定所有委托事件。这正是.live()被弃用的原因,因为当您以这种方式绑定许多事件时,效率非常低。对于委托事件处理,将它们绑定到非动态的最接近的父级要高效得多。
.live()
第三,不是所有事件都能奏效或所有问题都可以通过委托解决。例如,如果要拦截输入控件上的键事件并阻止将无效键输入到输入控件中,则不能使用委托事件处理来执行此操作,因为到事件冒泡到委托处理程序时,它已经已由输入控件处理,现在来影响该行为为时已晚。
在某些情况下,需要进行事件委派或有利于进行事件委派:
为了进一步了解这一点,需要了解jQuery委托事件处理程序的工作方式。当您调用类似这样的内容时:
$("#myParent").on('click', 'button.actionButton', myFn);
它将在#myParent对象上安装通用jQuery事件处理程序。当click事件冒泡到此委托事件处理程序时,jQuery必须遍历附加到此对象的委托事件处理程序列表,并查看事件的原始元素是否与委托事件处理程序中的任何选择器匹配。
#myParent
因为选择器可以相当广泛地参与其中,所以这意味着jQuery必须解析每个选择器,然后将其与原始事件目标的特征进行比较,以查看它是否与每个选择器匹配。这不是一个便宜的操作。如果只有一个选择器,这没什么大不了的,但是如果将所有选择器放在文档对象上,并且有数百个选择器要与每个冒泡事件进行比较,这会严重影响事件处理性能。
因此,您需要设置委托事件处理程序,以使委托事件处理程序尽可能接近目标对象。这意味着更少的事件将在每个委派的事件处理程序中冒泡,从而提高了性能。将所有委托事件放在文档对象上是最糟糕的性能,因为所有冒泡事件都必须经过所有委托事件处理程序并针对所有可能的委托事件选择器进行评估。这就是为什么.live()不赞成这样.live()做的原因,因为这样做是事实,并且事实证明效率很低。
因此,要实现优化的性能: