有效地测试元素是不是会在 jQuery 集合中

Posted

技术标签:

【中文标题】有效地测试元素是不是会在 jQuery 集合中【英文标题】:Efficiently test if an Element will be in a jQuery collection有效地测试元素是否会在 jQuery 集合中 【发布时间】:2018-09-09 21:07:02 【问题描述】:

给定一个像 $(selector,containerElement) 这样的 jQuery 集合,是否可以在不构建集合的情况下测试给定元素是否会成为该集合的一部分。

也就是说,不这样做:$(selector,containerElement).is(someElement),它将构造一个包含所有匹配元素的 jQuery 对象,然后检查其中一个元素是否为 someElement

有没有更有效的方法?

PS:请注意,jQuery 支持额外的选择器语法,如 :has():lt():first 和相对选择器,如 > tagName+ tagName

【问题讨论】:

jQuery 本身就非常高效。为什么需要这样做? @gforce301,当您需要频繁执行此操作时,例如在setInterval 回调或响应移动事件时,穷举方法不够快。 现在有 3-4 名用户将时间花在了可以避免的事情上,如果您考虑到所有奇怪的情况,制作一个简单的样本。 @LGSon 我认为 jQuery 支持比原生 API 更多的选择器是常识。我编辑了这个问题以明确这一点。 @GetFree 这是常识,但这些选择器在您的情况下可能有用,也可能没用。现在我们知道了。 【参考方案1】:

我最终为此实施了自己的自定义解决方案。 以下函数可以解决问题。

function jQueryMatch(selector, container, element)
    let attrName = '_dummy_876278983232' ;
    let attrValue = (''+Math.random()).slice(2) ;
    $(container).attr(attrName,attrValue) ;
    selector = selector.replace(/(,|^)(\s*[>~+])/g,`$1 [$attrName=$attrValue]$2`) ;
    return $(element).is(selector) ;

jQueryMatch(selector, container, element) 等价于$(selector, container).is(element)

我测得jQueryMatch 的速度提高了 3 到 10 倍,具体取决于选择器的复杂性。在更大的 DOM 树上,差异会更大。

这个函数非常简单,所以很容易弄清楚它的作用。

【讨论】:

【参考方案2】:

$.contains(containerElement, someElement);

【讨论】:

.contains() 仅检查元素是否为后代。 css 选择器可能更复杂。 好点,您也可以尝试使用 .filter() 并测试您的标准所需的等效性。【参考方案3】:

如果性能是个问题,你可以使用 vanilla JS,例如:

[...yourContainer.querySelectorAll('yourSelector')].includes(elementToTest)

示例

let container = document.querySelector('[data-container');
let insideElement = container.querySelector('[data-inside-element]');
let outsideElement = container.querySelector('[data-outside-element]');

console.log([...container.querySelectorAll('[data-inside-element]')].includes(insideElement));
console.log([...container.querySelectorAll('[data-inside-element]')].includes(outsideElement));
<div data-container>
  <p data-inside-element>element1</p>
  <p data-inside-element>element2</p>
  <p data-inside-element>element3</p>
</div>

<p data-outside-element>outside element</p>

【讨论】:

原生 DOM API 无法工作,因为 jQuery 支持额外的选择器语法,例如 $('&gt; div',container)$('+ div',container)$('~ div',container) 等。【参考方案4】:

扩展 Brian Reynolds 的回答:

$.contains(containerElement, someElement) && someElement.is(selector)

但是,如果 selector&gt;+~ 之类的运算符开头,这些运算符要求它位于相对于 containerElement 的特定位置,这将不起作用,因为我们已经分开那些变量。

【讨论】:

这不适用于像$('&gt; div',container)$('+ div',container)$('~ div',container)这样的相对选择器

以上是关于有效地测试元素是不是会在 jQuery 集合中的主要内容,如果未能解决你的问题,请参考以下文章

当您 remove() 一个元素并将其 append() 到别处时,事件是不是会在 jQuery 中丢失?

如何(有效地)生成不相交的集合,同时只使用一次元素对?

jQuery遍历

测试两个元素是不是相同

jquery怎么判断页面中是不是存在某元素

使用JQuery将文本添加到动态创建的HTML表中