4

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

我有一个事件对象。我正在通过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

4 回答 4

8

最近的()函数将满足您的需要。

它从元素本身开始,遍历父元素(朝向文档根),直到找到与提供的选择器字符串匹配的节点。有点类似于jQuery的parents()功能。

所以你的代码看起来像这样:

event.target.closest(selectorString)
于 2019-09-19T02:12:21.940 回答
4

To prevent redundant looping through all parent elements of your target element, you can perform quick checking for whether your element is inside of an element that matches your selector by using matchesSelector() with selector that is concatenation of your original selector and appended context selector consisting of space and your target-element's tag name:

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.
}
于 2012-12-17T16:17:27.970 回答
4

Marat Tanalin的解决方案很好,但标准语法elem.matchesSelectorelem.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 根本不支持此功能。

为了缓解这个问题,您可以按照 MDN的建议将描述的方法与以下polyfill结合起来:

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,这是所有现代浏览器都支持的功能。

浏览器支持:

在此处输入图像描述

于 2016-05-03T22:26:22.647 回答
1

大多数要求在 vanilla-js 中重新实现 jQueryparents()方法的问题都作为这个问题的重复而关闭,我想提供一个更现代的示例来更好地模拟 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
于 2020-09-08T15:45:10.113 回答