8

我花了一些时间搜索,但只看到太多常规的“walk the DOM”博客或答案,它们只升级一级getRootnode()

伪代码:

HTML

<element-x>
//# shadow-root
    <element-y>
        <element-z>
        //# shadow-root
        let container = this.closest('element-x');
        </element-z>
    </element-y>
</element-x>

标准element.closest()功能不会穿透阴影边界;

所以this.closest('element-x')返回null是因为shadowDom中没有 <element-x><element-z>

目标:

<element-x>从后代内部查找<element z>(任何嵌套级别)

必需的:

一个(递归).closest()函数,它沿着(影子)DOM 走找到<element-x>

注意:元素可能有也可能没有 ShadowDOM(参见<element y>:只有 lightDOM)

明天我可以而且会自己做;只是想知道是否一些聪明的头脑已经做到了。

资源:

更新

这是来自以下答案的 UNminified 代码:

        closestElement(selector, base = this) {
            function __closestFrom(el) {
                if (!el || el === document || el === window) return null;
                let found = el.closest(selector);
                if (found)
                  return found;
                else
                  __closestFrom(el.getRootNode().host);
            }

            return __closestFrom(base);
        }

更新#2

我将其更改为 BaseElement 上的方法:

  closestElement(selector, el = this) {
    return (
      (el && el != document && el != window && el.closest(selector)) ||
      this.closestElement(selector, el.getRootNode().host)
    );
  }
4

3 回答 3

6

这与任何子(影子)DOM 内部的.closest()相同

但走上 DOM跨越shadowroot 边界

针对(极端)缩小进行了优化

//declared as method on a Custom Element:
closestElement(
    selector,      // selector like in .closest()
    base = this,   // extra functionality to skip a parent
    __Closest = (el, found = el && el.closest(selector)) => 
        !el || el === document || el === window
            ? null // standard .closest() returns null for non-found selectors also
            : found 
                ? found // found a selector INside this element
                : __Closest(el.getRootNode().host) // recursion!! break out to parent DOM
) {
    return __Closest(base);
}

注意:__Closest 函数被声明为“参数”以避免额外的let声明......更好地缩小,并防止您的 IDE 抱怨

从自定义元素内部调用:

<element-x>
//# shadow-root
    <element-y>
        <element-z>
        //# shadow-root
        let container = this.closestElement('element-x');
        </element-z>
    </element-y>
</element-x>
于 2019-02-05T11:01:27.507 回答
4

优秀的例子!想要贡献一个有细微差别的 TypeScript 版本——它在遍历阴影根时遵循assignedSlot,因此您可以在嵌套的开槽自定义元素链中找到最接近的匹配元素。这不是编写 TypeScript 的最佳方式,但它可以完成工作。

closestElement(selector: string, base: Element = this) {
  function __closestFrom(el: Element | Window | Document): Element {
    if (!el || el === document || el === window) return null;
    if ((el as Slotable).assignedSlot) el = (el as Slotable).assignedSlot;
    let found = (el as Element).closest(selector);
    return found
      ? found
      : __closestFrom(((el as Element).getRootNode() as ShadowRoot).host);
  }
  return __closestFrom(base);
}

JS中的等价物是:

closestElement(selector, base = this) {
    function __closestFrom(el) {
        if (!el || el === document || el === window)
            return null;
        if (el.assignedSlot)
            el = el.assignedSlot;
        let found = el.closest(selector);
        return found
            ? found
            : __closestFrom(el.getRootNode().host);
    }
    return __closestFrom(base);
}
于 2019-05-13T03:24:23.220 回答
0

像这样的东西应该可以解决问题

function closestPassShadow(node, selector) {

    if (!node) {
        return null;
    }

    if (node instanceof ShadowRoot) {
        return this.closestPassShadow(node.host, selector);
    }

    if (node instanceof HTMLElement) {
        if (node.matches(selector)) {
            return node;
        } else {
            return this.closestPassShadow(node.parentNode, selector);
        }
    }

    return this.closestPassShadow(node.parentNode, selector);

}
于 2021-05-24T17:47:58.030 回答