2020年3月15日日曜日

Web components の使い方とポイント

Web components を使ってアプリを作って、思うところがあったのでまとめておきます。

1. Web components はみんなが学ぶ必要がありそう

最初に結論から言うと、Web components はフロントエンドを少しでもいじってる人は、みんな学ぶ必要がありそうと思いました。 私も最初は使いたい人だけ学べば良いかと思っていたけど、少しでも Web components を使ったテンプレートやライブラリを操ろうとすると、仕組みを知っていないときちんと扱えない。

JavaScript は ES5 時代は minimal でとても良かったんですが、最近はかなり広く知る必要が出てきています。 しかし Web components 回りのドキュメントは現状読みにくいものばかりだったので、自分用備忘録として重要なところだけまとめました。 ちなみに今のとこ一番 Web components の説明がわかりやすいかなと思ったのは以下です。 この記事はその補足みたいなもんです。

2. template の制約に注意

最近作っていたアプリで作った img-box という Shadow DOM を例に挙げます。 img-box は画像に閉じるボタン (svg のところ) を付けるだけの、シンプルな Shadow DOM です。
<template id="img-box">
  <style>
    .thumbnail { position:relative; float:left; padding:5px; }
    .toolbar { position:absolute; top:0; left:0; padding:10px; }
    svg { cursor: pointer; }
  </style>
  <div class="thumbnail">
    <img src="dummy.jpg" width="150" height="150" alt="thumbnail">
    <div class="toolbar">
      <svg class="close"> ... </svg>
    </div>
  </div>
</template>
<script>
customElements.define('img-box',
  class extends HTMLElement {
    constructor() {
      super();
      const template = document.getElementById('img-box')
        .content.cloneNode(true);
      template.querySelector('.close').onclick = function() {
        this.parentNode.parentNode.remove();
      };
      this.attachShadow({mode: 'open'}).appendChild(template);
    }
})
</script>
attachShadow などのお決まりみたいな部分は説明しませんが、Shadow DOM を定義するに当たっては 2 つ重要なポイントがあります。
  1. template 内の探索には querySelector / querySelectorAll しか使えない
  2. template 内のイベント定義は制約が多いのでコンストラクタで実装すべき
1 は、getElementById のような DOM 操作コマンドが使えないということです。 DOM 操作では速度を意識して get 系を使いたくなるので注意が必要。 たぶん通常のエレメントと処理を変えることで軽量化・高速化しているんでしょうねえ。

2 は JavaScript Framework に慣れた人はこれを Web components の不満としてよく挙げます。 ただコンストラクタで実装すれば何の問題もありません。 コンストラクタ以外だと、connectedCallback() に実装するのが良いかと。

どちらも、そういうものなのだと思えば、難しいところはないです。


3. Shadow DOM の呼び出しには独自メソッドを用いる

多くの人にはこちらが重要で、Shadow DOM の呼び出しには独自メソッドを用いる必要があります。 例として、Shadow DOM を呼び出して一部分だけ要素を書き換えてみます。
function snapToThumbnail() {
  affineImage();
  var thumbnail = document.createElement('img-box');  // img-box を生成して
  var img = thumbnail.shadowRoot.querySelector('img');  // 中の img タグを探して
  img.src = canvasCV.toDataURL('image/jpg');  // src を書き換える
  outputElement.append(thumbnail);  // 最後に body に img-box を出力する
}
このコードで重要なポイントは 2 つあります。
  1. Shadow DOM 内の探索には shadowRoot オブジェクト配下を見る必要がある
  2. Shadow DOM 内の探索には querySelector / querySelectorAll しか使えない
特に 1 が重要ですね。 「shadowRoot を通じてアクセスする」を知ってないと、探したい要素が見つからないで苦労するかと思います。 これがみんなが知っているべき理由。 iframe の処理でも独自のオブジェクト配下を見る必要がありますが、それに似ています。

Web components はイベント回りに踏み込まないように心掛ければ、ハマりそうなポイントはこれくらいです。 使うことが当たり前になれば結構使いやすい機能と思う。

0 件のコメント: