1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Web ComponentsでTheme Providerを実装する

Posted at

Web ComponentsでReactのThemeProviderのようなものを実装したい。

@ionic/coreのthemeの実装を読んだら感銘を受けたのでメモ

まとめ

  • Element.closest(selector)でDOM treeを逆向きに検索する
  • 実装に困ったら@ionic/coreを読む

実装

theme-provider

attribute変更の際にthemeの変更を適用したいという要求が無いなら、空のコンポーネントで良い

<template id="theme_provider">
  <slot></slot>
</template>
customElements.define(
  "theme-provider",
  class extends HTMLElement {
    constructor() {
      super();
      const template = document.getElementById("theme-provider");
      this.template = template.content;

      const shadowRoot = this.attachShadow({
        mode: "open"
      }).appendChild(template.content.cloneNode(true));
    }
  }
);

子コンポーネント

子コンポーネントは何でもいいですが、各テーマのstylesを用意しておきます

<template id="heading_level1">
  <style>
    h1.default {
      color: #333;
    }

    h1.christmas {
      color: green;
    }
  </style>
  <h1>
    <slot></slot>
  </h1>
</template>

customElements.define(
  "heading-level1",
  class extends HTMLElement {
    constructor() {
      super();
      const template = document.getElementById("heading_level1");
      this.template = template.content;

      const shadowRoot = this.attachShadow({
        mode: "open"
      }).appendChild(template.content.cloneNode(true));

      // theme-providerを探してthemeを登録する
      this.themeElement = this.closest('theme-provider');
      const theme = this.themeElement ? themeElement.getAttribute('theme') : '';
      this.shadowRoot.querySelector("h1").className = theme;
    }
  }
);

DOMツリーを親の方向に検索してThemeを取得する

DOMツリーの親方向に探索する場合はElement.closest(selector)

const theme = this.closest('theme-provider').getAttribute('theme');
this.shadowRoot.querySelector("h1").className = theme;

classNameをプログラマブルにしたい場合はclsxとかを使うと良いと思う

theme-providerが変更された場合に反映したい

動的にthemeを入れ替える必要がある場合は、その変更を子コンポーネントに通知したい。

theme-provider側:変更を外に通知するためにCustomEventを使う必要がある。

子コンポーネント側:初回のtheme取得と同じく、親Nodeを遡ってtheme-providerを見つけ、event listenerを登録しておく。

というdemoはCodepenに置きました。

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?