使用原生DOM的最近祖先匹配选择器?

时间:2013-03-10 23:49:16

标签: javascript jquery standards w3c dom-traversal

是否有人在DOM api中使用jQuery.closest()等效文件?

看起来Selectors Level 2 draft添加matches()等同于jQuery.is(),因此原生最接近应该更容易编写。是否已向选择器添加closest()

6 个答案:

答案 0 :(得分:35)

建立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

答案 1 :(得分:11)

答案 2 :(得分:5)

Element.closest()

its support

使用Element.matches()实现此类函数在性能方面似乎不是最佳的,因为看起来match()每次测试父级时都会调用querySelectorAll(),而只有一次调用就足够了。

这是MDN上最近()的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;
  };
}

但请记住,像这样实现的函数在unattached树上不能正常工作(与document.documentElement root分离)

//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中实现的nearest()似乎可以与分离树一起使用

document.documentElement.removeChild(detachedRoot);
child.closestTest("footer"); //null
child.closest("footer"); //<footer>

答案 3 :(得分:3)

考虑到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

答案 4 :(得分:1)

使用element.closest()我们可以找到最近的祖先匹配选择器。此方法将选择器列表作为参数并返回最近的祖先。根据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>

答案 5 :(得分:1)

一点点递归就可以了。

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