我正在开发/已经开发了一些系统,我在编程中遇到了一个问题,我似乎将所有我的JQuery函数委托给文档,如下所示:
$(document).on('click', '.modal-editor', function () {
//code
});
$(document).on('click', '.another-class', function () {
//code
});
$(document).on('click', '#another-id', function () {
//code
});
这有什么问题吗?
更新
好的,基本上没有任何问题,直到:
应用程序达到了一种规模,其中委托需要更加本地化以防止减慢UI。 “发生的每个事件都需要针对e.target和文档之间的每个元素运行每个选择器”
如果使用嵌套函数,这样的委托会增加传播等意外行为的可能性。
回到我的问题(最佳实践),最佳做法是将事件委托给最接近的静态元素,以试图避免上述情况。
答案 0 :(得分:4)
“这有什么问题吗?”
是。发生的每个事件都需要针对e.target
和document
之间的每个元素运行每个选择器。这是不必要的昂贵。
基本上就像这个简化的伪代码:
// start on the e.target
var node = e.target;
// For the target and all its ancestors until the bound element...
while (node && node !== this) {
// ...test the current node against every click selector it was given
for (var i = 0; i < click_selectors.length; i++) {
// If a selector matches...
if ($(node).is(selector)) {
// ...run the handler for that selector
}
}
node = node.parentNode;
}
此外,如果您加载的代码或其他代码在e.target
和document
之间绑定了处理程序,并且调用了e.stopPropagation()
,则该事件将永远不会到达{{1} ,所以你的不会开火。
让你的代表团尽可能接近预期的要素会好得多。并且主要用于动态加载的元素,因为它增加了额外的开销,特别是在事件快速激发的情况下。
答案 1 :(得分:3)
是。实际上并不是真的,但是委托document
(DOM的根)中的所有事件确实意味着所有点击事件,包括你所做的那些事件不感兴趣的将至少部分处理:
$(document).on('click', '$another-id', function(){});
在这方面,是一个特别糟糕的主意:你在单个元素之后,但是如果我点击身体的任何地方,jQ会做类似的事情:
if (event.target.id == 'another-id')
{
return callback.call(event.target, $(event));//where callback is the anonymous function you passed to on
}
return event;
所以所有点击事件都会导致函数调用。这可能会降低用户界面的速度
绝不应该停止委托事件,而是明智地绑定侦听器。例如,如果要使用的所有DOM元素都包含在#container
div中,那么将侦听器绑定在那里。如果要处理导航事件,请将侦听器绑定到包含所有导航元素的节点
除此之外,如果您取消某个事件但未能 stopPropagation ,则该事件仍将最终调用可能排队的所有其他侦听器。 Returnign false
也会造成麻烦,因为在jQ中,return false
被翻译为e.preventDefault(); e.stopPropagation()
。因此在处理嵌套元素时要小心,如果要处理页面中链接的点击,还要处理<a class='navigation'>
等元素,可能会调用两个处理程序,具体取决于选择器使用:
$(document).on('click', 'a', function(){});//is called for all links
$(document).on('click', 'a.navigation', function(){});//is called for navigation
首先会调用哪个?在特定情况下,您想要使用哪个?这里有错误的余地,不应该出现在那里:
$('#navContainer').on('click', 'a.navigation', function(){});//is called for all links
至少使事情更安全,更清晰,更轻松。
如果您想使用ID选择器委派一个事件,并且该元素已存在于DOM中,不委托:
$('#another-id').on('click', function(){});
更短,无论如何甚至可能更快
答案 2 :(得分:1)
您的代码没有任何问题,
$(document)
不一定要永远放在事件委托中,选择器是指动态添加元素的最接近的父元素:
语法:
$(closest parent selector).on('event','target selector', function(){
});
您也可以使用document.body
$(document.body).on('event','target selecor',function(){
});
旁注:对于现有的 DOM 元素,您可以使用普通点击事件。
$('selector').click(function(){
});
或强>
$('selector').on('click',function(){
});
有关更多信息,请参阅.on()
API文档。
答案 3 :(得分:1)
如果您希望将特定事件应用于多个元素,而不是每个元素都有自己的事件处理程序,那么委派就很棒。在上面的例子中,这可能是前两种方法。
如果只有一个元素符合理论上的标准,它可能会有一个性能含义,具体取决于文档的大小,因为必须针对处理程序过滤器测试每个事件以查看它是否匹配
此外,如果将每个方法添加为委托,并且您经常加载和上传页面的各个部分,那么这些事件将比它们所属的页面上的元素挂起的时间更长。
您可以将处理程序委派给文档元素以外的其他内容,例如周围的div
或其他内容,而不是在这种情况下。或者使用事件命名空间来确保不会多次添加事件。