使用本机DOM的最近祖先匹配选择器

Closest ancestor matching selector using native DOM?

本文关键字:祖先 选择器 最近 本机 DOM      更新时间:2023-09-26

是否有人在DOM api中使用jquery .close()等效?

看起来selector Level 2草案添加了等价于jQuery.is()的matches(),所以native close应该更容易编写。添加closest()到选择器上来了吗?

基于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;
}

浏览器支持:http://caniuse.com/matchesselector

似乎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.close()文档

用Element.matches()实现这样的函数在性能方面似乎不是最优的,因为很明显matches()将在每次测试父级时调用querySelectorAll(),而只调用一次就足够了。

这是MDN上的close()的多边形。注意,对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;
  };
}

但是请记住,像这样实现的函数将无法在未连接的树(从文档分离)上正常工作。documentElement根)

//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中实现的close()似乎可以很好地处理分离树

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的形式可用。

使用element.close()我们可以找到最接近的祖先匹配选择器。此方法将选择器列表作为参数,并返回最近的祖先。根据Rob的评论,这个API将从chrome 41和FF 35中提供。

如whatwg specs https://dom.spec.whatwg.org/#dom-element-closest所述

示例:下面的HTML将显示警告消息"true"

<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);
    };
})();