是否有人在DOM API中开发与jQuery.closest()相当的功能?
看起来Selectors Level 2草案添加了matches()
相当于jQuery.is(),因此原生的closest函数应该更容易编写。是否已经考虑将closest()
添加到Selectors中呢?
是否有人在DOM API中开发与jQuery.closest()相当的功能?
看起来Selectors Level 2草案添加了matches()
相当于jQuery.is(),因此原生的closest函数应该更容易编写。是否已经考虑将closest()
添加到Selectors中呢?
继Alnitak的答案之后,这里是使用matchesSelector
的当前实现版本,该方法在DOM规范中已更名为matches
。
// get nearest parent element matching selector
function closest(el, selector) {
var matchesSelector = el.matches || el.webkitMatchesSelector || el.mozMatchesSelector || el.msMatchesSelector;
while (el) {
if (matchesSelector.call(el, selector)) {
break;
}
el = el.parentElement;
}
return el;
}
.bind(ctx)(arg)
而不是.call(ctx, arg)
?前者创建一个新的执行上下文,而后者则不会。 - Alnitakcall(elem, selector)
的性能比 bind(elem)(selector)
更优,基准测试请看 http://jsperf.com/native-vs-jquery-closest。然而简单的 .parentNode.parentNode
方法速度更快。 - Binyamin似乎Chrome 40将带来一个原生的element.closest()
方法(http://blog.chromium.org/2014/12/chrome-40-beta-powerful-offline-and.html),在这里指定:https://dom.spec.whatwg.org/#dom-element-closest
使用 Element.matches() 来实现这样的函数在性能上似乎不太优秀,因为 matches() 显然会在每次测试父元素时调用 querySelectorAll(),而仅需一次调用即可完成工作。
以下是 MDN 上关于 closest() 的 polyfill。请注意只有一次对 querySelectorAll() 的调用。
if (window.Element && !Element.prototype.closest) {
Element.prototype.closest =
function(s) {
var matches = (this.document || this.ownerDocument).querySelectorAll(s),
i,
el = this;
do {
i = matches.length;
while (--i >= 0 && matches.item(i) !== el) {};
} while ((i < 0) && (el = el.parentElement));
return el;
};
}
//Element.prototype.closestTest = function(s){...as seen above...};
var detachedRoot = document.createElement("footer");
var child = detachedRoot.appendChild(document.createElement("div"));
detachedRoot.parentElement; //null
child.closestTest("footer"); //null
document.documentElement.append(detachedRoot);
child.closestTest("footer"); //<footer>
虽然Firefox 51.0.1中实现的closest()函数似乎可以很好地处理分离的树
document.documentElement.removeChild(detachedRoot);
child.closestTest("footer"); //null
child.closest("footer"); //<footer>
这听起来应该很容易,因为有 matches
函数,虽然目前它还没有被广泛支持:
function closest(elem, selector) {
while (elem) {
if (elem.matches(selector)) {
return elem;
} else {
elem = elem.parentElement;
}
}
return null;
}
问题在于,matches
函数得不到良好的支持。由于它是一个相对较新的API,在Chrome和Safari中可以使用webkitMatchesSelector
,在Firefox中可以使用mozMatchesSelector
。
*MatchesSelector
,只需使用本机 DOM 就可以轻松创建最接近的元素。我更好奇是否有任何动力将 element.closest(selector)
添加为元素的本机方法。 - hurrymaplelad<html>
<body>
<foo>
<bar>
<a id="a">
<b id="b">
<c id="c"></c>
</b>
</a>
</bar>
</foo>
<script>
var a = document.getElementById('a');
var b = document.getElementById('b');
var c = document.getElementById('c');
alert(c.closest("a, b")==b);
</script>
</body>
</html>
// get nearest parent element matching selector
var closest = (function() {
var matchesSelector = el.matches || el.webkitMatchesSelector || el.mozMatchesSelector || el.msMatchesSelector;
return function closest(el, selector) {
return !el ? null :
matchesSelector.call(el, selector) ? el : closest(el.parentElement, selector);
};
})();
element.tagName ==='HTML'? null:element.matches(selector)? element:closest(element.parentNode,selector);
;) - yckart
matches
分支的特征检测。这并不难,但可能会有点慢。 - RobGmatchesSelector
。 - hurrymaplelad