2019年5月8日水曜日

Web Componentsの仕組みをざっくり理解する

GooglebotでWeb ComponentsがサポートされWeb Componentsがどういうものかそろそろ理解したかったので、Googleの解説を見てみました。 自分用にわかりやすくリライトしてざっくりまとめると、JavaScriptの動作込みで再利用可能なタグを定義できる仕組みですね。 その定義にShadow DOMというものを使っている。Shadow DOM≒標準サポートされた仮想DOM、の理解で良いと思います。

どのように使えるかですが、モーダルウィンドウを作る場合を例にするとわかりやすいと思いました。 これまではCSSとJavaScriptをライブラリ側で定義して、そのタグ構造を利用者がコピペしてモーダルウィンドウを実現していました。 Bootstrapではそのコピペするべきコードが以下のようになっています。長いね。
<div class="modal" tabindex="-1" role="dialog">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title">Modal title</h5>
        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body">
        <p>Modal body text goes here.</p>
      </div>
    </div>
  </div>
</div>


Web Componentsを使うと、呼び出し側では例えば以下のように書けます。 書き方の定義はライブラリ内でするので、こんな感じで書けたら良いなーという願望です。
<modal>
  <modal-title slot='title'>Modal title</modal-title>
  <modal-body slot='body'>Modal body text goes here.</modal-body>
</modal>
ライブラリ側はどんな感じになっているかというと、以下のような実装になる。 ポイントはshadowRoot内で書き換えるHTML/CSSを定義して、その内部にあるslotタグで書き換える要素を定義するというところ。 connectedCallback() あたりの記述はJavaScriptで書き換えの時の処理を定義している。
<script>
customElements.define('modal', class extends HTMLElement) {
  constructor() {
    super();
  }
  let shadowRoot = this.attachShadow({mode:'open'});
  shadowRoot.innerHTML = `
    <style>
      ... 省略 ...
      modal { background:black; }  // 定義したWeb Componentsのスタイルも作れる
    </style>
    <div>  // 実際にはここでBootstrapのような構造を定義する
      <div id='modal-title'><slot id='title'></slot></div>
      <div id='modal-body'><slot id='body'></slot></div>
    </div>
  `;
  connectedCallback() {
    const modalTitle = this.shadowRoot.getElementById('modal-title');
    ... 色々な動作を定義 ...
  }
}
</script>
雑多な仕組みとしては、Shadow DOM特有のCSSプロパティとして::slotted, :host, :host-contextなどが使える。 JavaScript側ではslotchangeイベントなどが使えるようだ。 他にもtemplateタグとの併用がおすすめされている。 XSSを考慮してShadow DOM内でしか機能しないイベントなども色々あるようなので、このへんは実装する時に確認して欲しい。


ドキュメントを読んで感じたWeb Componentsの主な利点は以下です。
  • HTML/CSS/JavaScriptが隠蔽化されグローバル汚染が減る
  • 利用者側のコード量が減って簡潔に書けるようになる
  • 既存のライブラリのようなclass呼び出しではないのでたぶん高速に動作する

一部分の機能だけしかまとめてないけど、他にも色々な機能やモードがあるみたい。 CSSフレームワークの実装がガラッと変わりそうですね。 Bootstrap 5や他のライブラリも実装方式がめちゃくちゃ簡潔になりそうで、楽しみです。

0 件のコメント: