🐥

Web Componentsで子要素を取得したい

2022/11/12に公開約1,900字

Web Componentで子要素を取得するにはslotを使おう

Web Componentsで子要素を取得するには<slot>を使う

ElemntWithChildren.ts
class ElementWithChildren extends HTMLElement {
  connectedCallback() {
    const shadow = this.attachShadow({ mode: "open" });
    shadow.innerHTML = `
        <div>
          <slot></slot>
        </div>
      `;
  }
}

customElements.define("element-with-children", ElementWithChildren);

tsをコンパイルして色々して

index.html
<element-with-children>
  <p>子要素だぞ</p>
</element-with-children>

みたいにするとブラウザには

って出る

開発者ツールからDOMを見てみると

っていう変な感じになってる

slotに名前をつけよう

slotにname属性をつけると、対応するところに挿入してくれる

UserCard.ts
class UserCard extends HTMLElement {
  connectedCallback() {
    const shadow = this.attachShadow({ mode: "open" });
    shadow.innerHTML = `
      <div>
        Name: <slot name="username"></slot>
      </div>
      <div>
        Name: <slot name="birthday"></slot>
      </div>
    `;
  }
}

customElements.define("user-card", UserCard);
index.html
<user-card>
  <span slot="username">John Smith</span>
  <span slot="birthday">01.01.2001</span>
</user-card>

connectedCallback内ではinnerHTMLで子要素を取得するのはやめよう

connectedCallback内ではinnerHTMLで子要素を取得するのは多分あまりよくない

これは以下のような理由から:

  1. DOMは親要素→子要素の順にレンダリングされる
<parent>
  <child></child>
</parent>

という構成だったらparentのレンダリングはchildより先になる

  1. connectedCallbackは要素がDOMに挿入されたタイミングで走るけど、そのタイミングでは子要素がまだ作成されていない
<script>
customElements.define('user-info', class extends HTMLElement {

  connectedCallback() {
    alert(this.innerHTML); // connectedCallbackが走るタイミングではinnerHTMLは空
  }

});
</script>

<user-info>John</user-info>
  1. setTimeoutとかで子要素の作成を待つこともできるけど、それだったら素直にslotを使った方がいい

参考

https://ja.javascript.info/slots-composition
https://ja.javascript.info/custom-elements

Discussion

ログインするとコメントできます