如何访问嵌套 Web 组件的锚点?

How to access anchestor of nested web components?

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

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

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

我想从我的内部 Web 组件到达 connectedCallback() 中的 my-controller 组件:

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.`);
        }
    }


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


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

即使我在调用 connectedCallback() 之后遍历 DOM 树,当我从 <my-item> 开始时,我也无法超过 <span>

这是故意的吗?

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

我怎样才能从任何嵌套级别完全向上 DOM 树?

通常认为 inner/child 元素能够从 outer/parent 元素访问数据是不好的做法。

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

内部组件会派发一个事件让外部元素知道它需要一些东西,然后外部组件可以调用内部组件的函数或设置参数。

你可以这样做:

子元素

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);
    }
  );
}

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)) {
  ...
}

当您使用阴影 DOM 定义自定义元素内容时,您会创建一个独特的 DOM 树。 Shadow DOM 是一个没有根元素的 DocumentFragment。

因此,您无法通过 DOM 向上 parentElement 属性.

简单地到达其(直观的)祖先

要到达 Shadow DOM 的宿主元素,而不是 结合 host

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

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

如果你想得到一个祖先,你可以试试这个