使用matchesSelector js检查event.target.parentElement

时间:2012-10-19 15:34:50

标签: javascript events match

不关心旧的浏览器回退。另外,不能使用库。

我有一个事件对象。我正在通过matchesSelector:

测试针对css选择器的event.target

event['target'].matchesSelector('css selector here');

这样可行,并且:

event['target']['parentElement'].matchesSelector('css selector here');

...和

event['target']['parentElement']['parentElement'].matchesSelector('css selector here');

我正在寻找的是一些可能的对象方法,除了我的理解之外,我可以用来检查每个parentElement以进行匹配,而没有for循环。我的重点是效率。

谢谢!

4 个答案:

答案 0 :(得分:3)

为了防止在目标元素的所有父元素中进行冗余循环,您可以使用matchesSelector()使用带有原始选择器串联的选择器快速检查元素是否在与选择器匹配的元素内部和附加的上下文选择器由space和target-element的标记名称组成:

function getAncestorBySelector(elem, selector) {
    if (!elem.matchesSelector(selector + ' ' + elem.tagName)) {
        // If element is not inside needed element, returning immediately.
        return null;
    }

    // Loop for finding an ancestor element that matches your selector.
}

答案 1 :(得分:3)

Marat Tanalin的解决方案很好,但elem.matchesSelector的标准语法是elem.matches

function getAncestorBySelector(elem, selector) {
    if (!elem.matches(selector + ' ' + elem.tagName)) {
        // If element is not inside needed element, returning immediately.
        return null;
    }

    // Loop for finding an ancestor element that matches your selector.
}

不幸的是,并非所有浏览器都支持此语法。一些浏览器仍然实现了elem.matchesSelector的前缀版本,Opera Mini根本不支持此功能。

要解决此问题,您可以将描述的方法与以下polyfill合并为suggested by the MDN

if (!Element.prototype.matches) {
    Element.prototype.matches = 
        Element.prototype.matchesSelector || 
        Element.prototype.mozMatchesSelector ||
        Element.prototype.msMatchesSelector || 
        Element.prototype.oMatchesSelector || 
        Element.prototype.webkitMatchesSelector ||
        function(s) {
            var matches = (this.document || this.ownerDocument).querySelectorAll(s),
                i = matches.length;
            while (--i >= 0 && matches.item(i) !== this) {}
            return i > -1;            
        };
}

或者,您可能要考虑完全抛弃elem.matchesSelector并使用以下内容:

function getAncestorBySelector(elem, selector) {
    if([].indexOf.call(document.querySelectorAll(selector + ' ' + elem.tagName), elem) === -1) {
        // If element is not inside needed element, returning immediately.
        return null;
    }
    // Loop for finding an ancestor element that matches your selector.
}

这两种实现至少需要querySelectorAll的支持,这是所有现代浏览器都支持的功能。

浏览器支持:

enter image description here

答案 2 :(得分:3)

closest()函数将满足您的需求。

它从元素本身开始,并遍历父级(朝向文档根目录),直到找到与所提供的selectorString匹配的节点。有点类似于jQuery的parents()函数。

因此您的代码将如下所示:

event.target.closest(selectorString)

答案 3 :(得分:0)

大多数要求在vanilla-js中重新实现jQuery的parents()方法的问题都作为该问题的重复部分而关闭,我想提供一个更现代的示例,更好地模仿jQuery的行为。

打字稿:

function getAllParentElements(child: HTMLElement, selector: string = '*') {
    const parents: HTMLElement[] = [];

    let parent: HTMLElement = child.parentElement?.closest(selector);
    while (parent) {
        parents.push(parent);
        parent = parent.parentElement?.closest(selector);
    }

    return parents;
}

JavaScript:

function getAllParentElements(child, selector = '*') {
    const parents = [];

    let parent = child.parentElement && child.parentElement.closest(selector);
    while (parent) {
        parents.push(parent);
        parent = parent.parentElement && parent.parentElement.closest(selector);
    }

    return parents;
}
getAllParentElements(childEl); // -> return all ancestors including body & html elements
getAllParentElements(childEl, '.foo'); // -> return all ancestors with `.foo` class