如何访问嵌套Web组件的祖先?

问题描述 投票:0回答:3

我正在为我的Web组件实现Orchestrator模式,如下所示:

<body>
  <my-controller>
    <div>
      <my-list>
        <span>
          <my-item></my-item>
        </span>
      </my-list>
    </div>
  </my-controller>
</body>

我创建的所有自定义元素都使用const root = super.attachShadow({mode: "open"}); root.appendChild(...);来使用Shadow DOM。

从我的内部Web组件,我想在my-controller中访问我的connectedCallback()组件:

public connectedCallback(): void
    {
        if (this.isConnected)
        {
            for (let node = this.parentElement; node; node = node.parentElement)
                if (node instanceof ContainerBase)
                {
                    this._service = (<ContainerBase>node).GetService(this);
                    break;
                }

            if (this._service) this.Reset();
            else throw new ReferenceError(`${this.nodeName.toLowerCase()}: Couldn't find host element while connecting to document.`);
        }
    }

奇怪的是:我只能到达直接的父网页控件。

因此,如果在connectedCallback()上调用<my-list>,我可以到达<my-controller>,但如果在connectedCallback()上调用<my-item>,我只能到达<span>。当我用<my-list>开始搜索时,我甚至无法到达<my-item>

甚至当我在调用connectedCallback()之后走DOM树时,当我开始在<span>时,我无法超越<my-item>

这是故意吗?

为什么我可以从第一个嵌套的组件到达外部Web组件,而我无法从第二个嵌套的Web组件到达第一个嵌套的Web组件?

如何从任何嵌套级别完全上升DOM树?

javascript google-chrome web-component shadow-dom custom-element
3个回答
2
投票

使用Shadow DOM定义自定义元素内容时,可以创建不同的DOM树。 Shadow DOM是一个没有根元素的文档片段。

因此,您无法通过parentElement属性向上移动DOM来达到其(直观)祖先。

要到达Shadow DOM的主机元素,而不是use getRootNode()host相结合。

来自<my-item>connectedCallback()方法:

connectedCallback() {
   var parent = this.getRootNode().host
   console.log( parent.localNode ) // my-list
}

如果你想要一个祖先,你可以试试这个recursive function


1
投票

通常认为内部/子元素能够从外部/父元素访问数据是不好的做法。

使用来自外部组件捕获的内部组件的自定义事件更安全且更少耦合。

内部组件将调度一个事件,让外部元素知道它需要某些东西,然后外部组件可以调用函数或在内部组件上设置参数。

你可以这样做:

儿童元素

connectedCallback() {
  this.dispatch(new CustomEvent('request-service'));
}

set service(val) {
  this._service = val;
}

get service() {
  return this._service;
}

服务要素:

constructor() {
  super();
  this.addEventListener('request-service',
    evt => {
      evt.target.service = this.GetService(evt.target);
    }
  );
}

0
投票

ShadowRoot不是一个元素,ShadowRootparentNode不是它的主元素。你需要照顾他们。

function shadowIncludingParentElement(node) {
  if (node.parentElement)
    return node.parentElement;
  if (!node.parentNode)
    return null;
  if (node.parentNode.nodeType == Node.DOCUMENT_FRAGMENT_NODE)
    return node.parentNode.host;
  return null;
}

...
for (let node = this.parentElement; node;
    node = shadowIncludingParentElement(node)) {
  ...
}
© www.soinside.com 2019 - 2024. All rights reserved.