在jQuery中优化实时元素的选择器

Optimize live elements' selectors in jQuery

本文关键字:元素 选择器 实时 优化 jQuery      更新时间:2023-09-26

我在下面的一些链接中读到了很多关于jQuery优化的信息:

  1. jQuery网站,性能
  2. jQuery 最佳实践 - Greg Franko
  3. jQuery 编码标准和最佳实践
  4. 14 个有用的 jQuery 技巧、注释和最佳实践

以及更多...但是他们都没有提到 .on() 缓存选择器。我不知道是否有任何方法可以在这些选择器中使用缓存元素。

例如,我的script.js文件中有很多这样的选择器。

$(document).on('click', '.menu li.remove', function(e){ ... });
$(document).on('click', '.menu li.edit', function(e){ ... });
$(document).on('click', '.menu li.action', function(e){ ... });
$(document).on('click', '.menu li.anotherAction', function(e){ ... });

等等。 .menu是一个菜单,可以在文档中的任何位置,所以我不能使用特定的id容器来选择它。喜欢这个:

$('#sidebar').on('click', '.menu li.action', function(e){ ... });

有没有办法优化这些选择器。检查是否存在,如果可能,则缓存.menu

当你需要挖掘出最后一点性能时,你可能需要抛弃抽象。

如果您自己进行委派,您肯定会看到性能改进。

因为在您给出的示例中,除了类名之外,所有委托都是相同的,所以我会绑定一个处理程序,将代码放在单独的函数中,然后手动检查e.target及其祖先以查找.menu li。如果找到,则检查li的类,并调用正确的处理程序。

var handlers = {
    remove: function() {/*your code*/},
    edit: function() {/*your code*/},
    action: function() {/*your code*/},
    anotherAction: function() {/*your code*/}
};
var targets = Object.keys(handlers);
document.onclick = function(e) {
    e = e || window.event;
    var li;
    var node = e.target || e.srcElement;
    var targetClass;
    do {
        if (!li) {
            if (node.nodeName === "LI") {
                li = node;
            }
        } else if (node.className.indexOf("menu") > -1) {
            targetClass = li.className
            break;
        }
    } while(node = node.parentNode);
    if (!targetClass)
        return;
    for (var i = 0; i < targets.length; i++) {
        if (targetClass.indexOf(targets[i]) > -1) {
            handlers[targets[i]].call(li, e);
        }
    }
}

在上面的代码中,当我们从e.target向上遍历时,我们首先检查我们是否在li上。如果是这样,请抓住它并继续一个。

随着我们的继续,我们不再需要检查li元素,但现在我们需要检查具有 menu 类的元素。如果我们找到一个,我们获取之前找到的li的类名,然后停止循环。

我们现在知道我们有我们的menu li.someClass元素。因此,我们可以使用我们在li上找到的类从我们上面创建的函数列表中查找要调用的正确函数。


您应该注意,我的.indexOf()类测试是临时的,可能会导致误报。你应该改进它。此外,代码需要更多的调整,因为我们缓存li而不知道它是否真的有一个我们感兴趣的类。这也应该得到解决。

如果您愿意,我会让您添加必要的调整。

我个人认为您担心速度不是问题。

如果菜单不是动态加载的,没有什么能阻止您将委托的事件处理程序与普通的 jQuery 选择器相结合,以针对更多更近的元素(例如您的 .menu 类):

例如

$('.menu').on('click', 'li.remove', function(e){ ... })
 .on('click', 'li.edit', function(e){ ... })
 .on('click', 'li.action', function(e){ ... })
 .on('click', 'li.anotherAction', function(e){ ... });

这将在每个菜单上创建一个处理程序(以便更接近元素)。

如果您的菜单是动态加载的,那么您现有的代码就完全没问题,因为我的理解是委托的事件处理程序仅将 selector 参数应用于气泡链中的元素。如果是这种情况,无论如何,委派事件将非常快。肯定比你点击鼠标快!我从来没有遇到过委托事件处理程序的速度问题,我可能在我的插件中过度使用它们(我总是假设其中的动态内容)。