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

时间:2022-11-29 10:23:09

Is anybody working on a jQuery.closest() equivalent in the DOM api?

是否有人在DOM api中处理jQuery.closest()等价物?

Looks like the Selectors Level 2 draft adds matches() equivalent to jQuery.is(), so native closest should be much easier to write. Has adding closest() to Selectors come up?

看起来选择器级别2草案添加了相当于jQuery.is()的matches(),因此本机最接近应该更容易编写。是否添加了最接近的选择器()?

6 个解决方案

#1


4  

Element.closest()

its support

Implementing such function with Element.matches() seems not optimal in terms of performance, cause apparently matches() will make a call to querySelectorAll() every time you test a parent, while only one call is sufficient for the job.

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

Here's a polyfill for closest() on MDN. Note a single call to 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;
  };
}

But bear in mind that function implemented like this will not work properly on unattached tree (detached from document.documentElement root)

但请记住,像这样实现的函数将无法在未附加的树上正常工作(与document.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>   

Though closest() that is implemented in Firefox 51.0.1 seems to work fine with detached tree

虽然在Firefox 51.0.1中实现的nearest()似乎可以与分离树一起使用

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

#2


35  

Building off of Alnitak's answer. Here's the working current implementation with matchesSelector which is now matches in the DOM spec.

建立Alnitak的答案。这是使用matchesSelector的工作当前实现,它现在在DOM规范中匹配。

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

Browser support is great: http://caniuse.com/matchesselector

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

#3


11  

Seems like Chrome 40 will bring a native element.closest() method (http://blog.chromium.org/2014/12/chrome-40-beta-powerful-offline-and.html) specified here: https://dom.spec.whatwg.org/#dom-element-closest

好像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

#4


3  

This sounds like it ought to be pretty easy, given the matches function, although that's not widely supported yet:

考虑到匹配功能,这听起来应该很容易,尽管这还没有被广泛支持:

function closest(elem, selector) {
    while (elem) {
        if (elem.matches(selector)) {
            return elem;
        } else {
            elem = elem.parentElement;
        }
    }
    return null;
}

The trouble is, the matches function isn't properly supported. As it's still a relatively new API it's available as webkitMatchesSelector in Chrome and Safari, and mozMatchesSelector in Firefox.

麻烦的是,匹配功能没有得到适当的支持。由于它仍然是一个相对较新的API,因此可以在Chrome和Safari中使用webkitMatchesSelector,在Firefox中使用mozMatchesSelector。

#5


1  

Using element.closest() we can find Closest ancestor matching selector. This method takes selectors list as parameter and returns the closest ancestor. As per Rob's Comment this API will be available from chrome 41 and FF 35.

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

As explained in whatwg specs https://dom.spec.whatwg.org/#dom-element-closest

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

Example: The below HTML will show alert message "true"

示例:以下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>

#6


1  

A little recursion will do the trick.

一点点递归就可以了。

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

#1


4  

Element.closest()

its support

Implementing such function with Element.matches() seems not optimal in terms of performance, cause apparently matches() will make a call to querySelectorAll() every time you test a parent, while only one call is sufficient for the job.

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

Here's a polyfill for closest() on MDN. Note a single call to 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;
  };
}

But bear in mind that function implemented like this will not work properly on unattached tree (detached from document.documentElement root)

但请记住,像这样实现的函数将无法在未附加的树上正常工作(与document.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>   

Though closest() that is implemented in Firefox 51.0.1 seems to work fine with detached tree

虽然在Firefox 51.0.1中实现的nearest()似乎可以与分离树一起使用

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

#2


35  

Building off of Alnitak's answer. Here's the working current implementation with matchesSelector which is now matches in the DOM spec.

建立Alnitak的答案。这是使用matchesSelector的工作当前实现,它现在在DOM规范中匹配。

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

Browser support is great: http://caniuse.com/matchesselector

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

#3


11  

Seems like Chrome 40 will bring a native element.closest() method (http://blog.chromium.org/2014/12/chrome-40-beta-powerful-offline-and.html) specified here: https://dom.spec.whatwg.org/#dom-element-closest

好像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

#4


3  

This sounds like it ought to be pretty easy, given the matches function, although that's not widely supported yet:

考虑到匹配功能,这听起来应该很容易,尽管这还没有被广泛支持:

function closest(elem, selector) {
    while (elem) {
        if (elem.matches(selector)) {
            return elem;
        } else {
            elem = elem.parentElement;
        }
    }
    return null;
}

The trouble is, the matches function isn't properly supported. As it's still a relatively new API it's available as webkitMatchesSelector in Chrome and Safari, and mozMatchesSelector in Firefox.

麻烦的是,匹配功能没有得到适当的支持。由于它仍然是一个相对较新的API,因此可以在Chrome和Safari中使用webkitMatchesSelector,在Firefox中使用mozMatchesSelector。

#5


1  

Using element.closest() we can find Closest ancestor matching selector. This method takes selectors list as parameter and returns the closest ancestor. As per Rob's Comment this API will be available from chrome 41 and FF 35.

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

As explained in whatwg specs https://dom.spec.whatwg.org/#dom-element-closest

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

Example: The below HTML will show alert message "true"

示例:以下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>

#6


1  

A little recursion will do the trick.

一点点递归就可以了。

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