【发布时间】:2011-03-19 07:01:02
【问题描述】:
有什么方法可以测试选择器是否匹配给定的 DOM 元素?最好不要使用像 Sizzle 这样的外部库。这是一个库,我想尽量减少“核心”库所需的第三方插件的数量。如果它最终需要 Sizzle,我将把它作为插件添加到库中,供那些想要它启用的功能的人使用。
例如,我可以这样做:
var element = <input name="el" />
matches("input[name=el]", element) == true
编辑:经过深思熟虑,我想出了一个解决方案,这在技术上是可行的,但在效率方面似乎不是最优的:
function matchesSelector(selector, element) {
var nodeList = document.querySelectorAll(selector);
for ( var e in nodeList ) {
return nodeList[e] === element;
}
return false;
}
基本上,该函数使用给定的选择器查询整个文档,然后遍历 nodeList。如果给定元素在 nodeList 中,则返回 true,否则返回 false。
如果有人能提出更有效的答案,我很乐意将他们的回答标记为答案。
编辑:Flavius Stef 向我指出了针对 Firefox 3.6+ 的浏览器特定解决方案,mozMatchesSelector。我还找到了 Chrome 的等价物(版本兼容性未知,它可能在 Safari 或其他 webkit 浏览器上工作也可能不工作):webkitMatchesSelector,这与 Firefox 实现基本相同。我还没有找到任何 IE 浏览器的原生实现。
对于上面的例子,用法是:
element.(moz|webkit)MatchesSelector("input[name=el]")
似乎 W3C 在 Selectors API Level 2(目前仍是草案)规范中也解决了这个问题。 matchesSelector 将成为 DOM 元素上的一个方法,一旦获得批准。
W3C 用法:element.matchesSelector(selector)
由于该规范仍然是一个草案,并且一旦成为标准,流行的浏览器在实现这些方法之前还有一段延迟,因此可能需要一段时间才能真正使用。好消息是,如果您使用任何流行的框架,它们很可能会为您实现此功能,而不必担心跨浏览器的兼容性。虽然这对我们这些不能包含第三方库的人没有帮助。
实现此功能的框架或库:
http://www.prototypejs.org/api/element/match
http://developer.yahoo.com/yui/docs/YAHOO.util.Selector.html
http://docs.jquery.com/Traversing/is
http://extjs.com/deploy/dev/docs/output/Ext.DomQuery.html#Ext.DomQuery-methods
http://base2.googlecode.com/svn/doc/base2.html#/doc/!base2.DOM.Element.matchesSelector
【问题讨论】:
-
我无法想象你会如何做到这一点——假设你想要支持广泛的选择器,或者所有 CSS2 或 3 选择器——无论如何都不会非常接近重新实现 Sizzle。既然已经优化和调试过了,为什么不直接使用呢?
-
@Pointy:我希望有一种方法可以通过现代浏览器中的内置选择器引擎(通过 querySelector 和 querySelectorAll)“本地”完成。如果没有,就像我说的那样,我将求助于使用库,但将此功能委托给插件,这样我的“核心”库就不需要 Sizzle。
-
Firefox 3.6 有 Node.mozMatchesSelector(): developer.mozilla.org/en/DOM/Node.mozMatchesSelector
-
@Flavius Stef:看起来还没有任何跨浏览器的方法可以做到这一点,但感谢您提供的链接,我按照 W3C 的 2 级规范进行操作,发现他们已经解决了这个问题,所以这只是规范的最终确定和实现它的浏览器的问题。如果您在自己的回复中添加有关在“W3C 选择器 API 级别 2(初稿)”中包含 matchSelector 方法的更多信息,我会将其标记为答案。如果没有,我会将其编辑到我的帖子中。
-
使用 Modernizr,您可以使用
Modernizr.prefixed('MatchesSelector,element)来获取具有正确(或没有)供应商前缀的函数(如果存在),然后可以将其用作fn && fn(selector)。