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

Javascript 使用本机DOM的最近祖先匹配选择器?,javascript,jquery,standards,w3c,dom-traversal,Javascript,Jquery,Standards,W3c,Dom Traversal,有人在使用DOM api中的等效程序吗 看起来addsmatches()相当于,因此本机最接近应该更容易编写。向选择器添加最近的()的功能出现了吗?考虑到该功能,这听起来应该很容易,尽管还没有得到广泛支持: function closest(elem, selector) { while (elem) { if (elem.matches(selector)) { return elem; } else {

有人在使用DOM api中的等效程序吗


看起来adds
matches()
相当于,因此本机最接近应该更容易编写。向选择器添加
最近的()
的功能出现了吗?

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

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

问题是,
匹配
功能未得到正确支持。由于它仍然是一个相对较新的API,在Chrome和Safari中可以作为
webkitMatchesSelector
使用,在Firefox中可以作为
mozMatchesSelector
使用。

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

浏览器支持非常好:

看起来Chrome 40将带来一个本地
元素。这里指定的最接近()方法:

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

如whatwg规范所述

示例:下面的HTML将显示警报消息“true”


var a=document.getElementById('a');
var b=document.getElementById('b');
var c=document.getElementById('c');
警报(c.最近的(“a,b”)==b);

一点递归就可以了

// 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.matches()实现这样的函数在性能上似乎不是最优的,因为显然matches()会在每次测试父级时调用querySelectorAll(),而只有一个调用就足够了

这里是MDN上最近()的多边形填充。注意对querySelectorAll()的单个调用

if(window.Element&&!Element.prototype.closest){
Element.prototype.closest=
职能{
var matches=(this.document | | this.ownerDocument).querySelectorAll,
我
el=这个;
做{
i=长度;
而(-i>=0&&matches.item(i)!==el{};
}而((i<0)&(el=el.parentElement));
返回el;
};
}
但请记住,这样实现的函数在独立树(从document.documentElement根分离)上无法正常工作

//Element.prototype.closestTest=函数{…如上所示…};
var detachedRoot=document.createElement(“页脚”);
var child=detachedRoot.appendChild(document.createElement(“div”));
detachedRoot.parentElement//无效的
子项关闭测试(“页脚”)//无效的
document.documentElement.append(detachedRoot);
child.closestTest(“页脚”);//
虽然Firefox 51.0.1中实现的最接近()似乎可以很好地处理分离树

document.documentElement.removeChild(detachedRoot);
child.closestTest("footer"); //null
child.closest("footer"); //<footer>
document.documentElement.removeChild(detachedRoot);
子项关闭测试(“页脚”)//无效的
最近的子项(“页脚”)//

只有当所有浏览器都实现了它们没有实现的方法时,“应该更容易”:-(因此,无论如何都必须编写一个直接的方法,我猜是用
macthes
fork的特性检测。这并不难,但可能有点慢。是的,回到供应商前缀
matchesSelector
。是的,使用
*matchesSelector
,只使用本机DOM快速生成一个最接近的方法变得很容易。我更好奇的是,如果添加
元素。最近的(选择器)
作为元素的本机方法背后有什么动力吗?@Hurrymapelad您可能必须加入W3C并提出建议。考虑到它的实现有多容易(根据上面的代码),我想他们不会介意的。我很难过。感谢您的实现,但这是否意味着本机最近的调用不会出现?为什么
.bind(ctx)(arg)
而不是
.call(ctx,arg)
?前者创建新的执行上下文,后者不会。
调用(elem,selector)
绑定(elem)(selector)有更好的性能
,基准测试。仍然很简单
。parentNode.parentNode
方法速度非常快。为什么返回false,而不是null?很好的调用。感谢yall!
元素。最近的
已登录到Chrome 41,而不是40(请参阅)。而且它也已登录。您也可以在较旧的浏览器上使用polyfill来使用此功能,例如,或者仅使用
return element.tagName==“HTML”?null:element.matches(selector)?element:closest(element.parentNode,selector);
;)根据MDN,似乎不再是“实验性的”:
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>   
document.documentElement.removeChild(detachedRoot);
child.closestTest("footer"); //null
child.closest("footer"); //<footer>