Web 组件:如何从父组件访问子组件实例

发布于 2025-01-11 23:09:22 字数 1122 浏览 2 评论 0原文

编辑我在这个问题中遗漏了一些细节,但假设这两个元素已经定义。此外,在现实世界的问题中,DOM 树更大,子组件插入到父组件中。找到子组件没有问题。

我有两个 Web 组件:ParentChild

我可能会在标记中使用这些组件,如下所示:

<parent-element>
  <child-element></child-element>
</parent-element>

Child 组件具有我想要向父级公开的逻辑。

class Child extends HTMLElement {
  constructor() {
    ...
  }

  publicMethod() {
    console.log('call me from the parent component');
  }
}

理想情况下,我想像这样从父级调用子方法:

class Parent extends HTMLElement {
  constructor() {
    ...
  }

  someTrigger() {
    const child = this.shadowRoot.querySelector('child-element');
    child.publicMethod();
  }
}

但这不起作用,因为 child 是一个 HTMLElement,因为 querySelector() API 返回 HTMLElement,而不是 Web 组件实例

有没有办法以类似的方式获取组件的实例?我希望能够遍历 Parent 组件影子树以查找特定的组件实例。

EDIT I've left out some details in this question, but assume that both of these elements are already defined. Also, in the real world problem, the DOM tree is bigger and the child component is slotted into the parent. There's no issue with finding the child component.

I have two web components: Parent and Child.

I might use these components in markup like this:

<parent-element>
  <child-element></child-element>
</parent-element>

The Child component has logic I want to expose to the parent.

class Child extends HTMLElement {
  constructor() {
    ...
  }

  publicMethod() {
    console.log('call me from the parent component');
  }
}

Ideally, I'd like to call the child method from the parent like this:

class Parent extends HTMLElement {
  constructor() {
    ...
  }

  someTrigger() {
    const child = this.shadowRoot.querySelector('child-element');
    child.publicMethod();
  }
}

This doesn't work, though, since child is an HTMLElement, because the querySelector() API returns an HTMLElement and not the web component instance.

Is there a way I can get the component's instance in a similar fashion? I'd like to be able to traverse the Parent components shadow tree to find a specific component instance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

蹲墙角沉默 2025-01-18 23:09:22

小心 whenDefined;
它告诉您 Web 组件已定义,而不是在 DOM 中解析

只要您保留 lightDOM 中, 和 ShadowDOM 与它们无关。

.as-console-wrapper {max-height:100%!important;top:0;zoom:.88}
.as-console-row:nth-child(n-6) {background:#0057B7!important;color:#FFD500!important}
.as-console-row:nth-child(n+6) {background:#FFD500!important;color:#0057B7!important}
.as-console-row-code{padding:0!important}
<script>
  console.clear();
  class Component extends HTMLElement {
    constructor() {
      super();
      console.log(this.nodeName, "constructor")
    }
    connectedCallback(){
      console.log("connectedCallback", this.nodeName, this.children.length, "children");      
    }
  }
  customElements.define("child-component", class extends Component {
    foo() {
      console.log("Executed <child-element>.foo()");
    }
  });
  customElements.define("parent-component", class extends Component {
    connectedCallback() {
      super.connectedCallback();
      customElements.whenDefined('child-component')
                    .then(() => console.log("Promise resolved, <child-component> IS defined!"));
      setTimeout(() => { // wait till lightDOM is parsed
        console.log("After setTimeout",this.nodeName,"has", this.children.length, "children");
        this.querySelectorAll("child-component").forEach(child => child.foo());
      })
    }
  })
</script>
<parent-component>
  <child-component></child-component>
  <child-component></child-component>
</parent-component>

Be careful with whenDefined;
it tells you the Web Component was defined, NOT when it was parsed in the DOM:

As long as you keep the <child-element> in lightDOM, <slot> and shadowDOM have nothing to do with them.

.as-console-wrapper {max-height:100%!important;top:0;zoom:.88}
.as-console-row:nth-child(n-6) {background:#0057B7!important;color:#FFD500!important}
.as-console-row:nth-child(n+6) {background:#FFD500!important;color:#0057B7!important}
.as-console-row-code{padding:0!important}
<script>
  console.clear();
  class Component extends HTMLElement {
    constructor() {
      super();
      console.log(this.nodeName, "constructor")
    }
    connectedCallback(){
      console.log("connectedCallback", this.nodeName, this.children.length, "children");      
    }
  }
  customElements.define("child-component", class extends Component {
    foo() {
      console.log("Executed <child-element>.foo()");
    }
  });
  customElements.define("parent-component", class extends Component {
    connectedCallback() {
      super.connectedCallback();
      customElements.whenDefined('child-component')
                    .then(() => console.log("Promise resolved, <child-component> IS defined!"));
      setTimeout(() => { // wait till lightDOM is parsed
        console.log("After setTimeout",this.nodeName,"has", this.children.length, "children");
        this.querySelectorAll("child-component").forEach(child => child.foo());
      })
    }
  })
</script>
<parent-component>
  <child-component></child-component>
  <child-component></child-component>
</parent-component>

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文