【Web Componentsを学ぶ】HTML Template編

# はじめに
この記事ではWeb Componentsを利用する準備のためにHTML Templateを紹介する記事です。Web Componentsとは他のコードから独立して利用できる再利用可能なコンポーネント(要素)を指します。
Web Componentを利用するために必要な他の要素として[Custom Elementについての記事](https://qiita.com/KokiSakano/items/1ffa65a1adb3f7c11112)、[Shadow DOMについての記事](https://qiita.com/KokiSakano/items/21e511313e64e70c2221)も書きましたので併せてご覧ください。なお、この記事ではCustom Elementは知らなくても進めることができますがShadow DOMについての知識は多少要求します。また、Web Components自体の実装は[こちらの記事](https://qiita.com/KokiSakano/items/334e0b3af7d72ee4d230)で行いました。

# HTML Templateとは
`template`と`slot`の二つの要素はHTMLに表示されないHTMLのテンプレートを書くことができ、それをHTML Template呼びます。Vueを触ったことがある方にとっては親近感のある要素なのではないでしょうか。JavaScriptを用いることでテンプレートは繰り返し使うことができます。

# template
まずは`template`をHTMLに埋め込むだけでは何も表示されないことを確認します。
<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="PoaxxNZ" data-editable="true" data-user="kokisakano" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/kokisakano/pen/PoaxxNZ">
  template01</a> by KokiSakano (<a href="https://codepen.io/kokisakano">@kokisakano</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

次にJavaScriptを操作して、`body`に`template`のcontentを渡してみます。
<p class="codepen" data-height="300" data-default-tab="js,result" data-slug-hash="abKQQNQ" data-editable="true" data-user="kokisakano" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/kokisakano/pen/abKQQNQ">
  template02</a> by KokiSakano (<a href="https://codepen.io/kokisakano">@kokisakano</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

そのままでは表示されませんでしたが、`template`の内部をとってきて`body`に追加することで表示することができました(当然と言えば当然ですが)。`template`の中身をとってくるときに`cloneNode`を使いました。これをしないとある場所で中身を変更すると他の場所にも変更が伝わって意図しない挙動になるからです(引数をtrueとすることでその子要素も全てコピーされます)。
`template`を用いることでJavaScriptでHTMLを文字列で扱ってDOMに追加する必要がなくなりとても綺麗に書くことができました。コードの綺麗さの観点の他にも文字列をHTMLとして扱うための変換も必要なくなるのでパフォーマンス上もとても有利です。

# slot
`slot`は`template`内部で使用する要素です。`template`の中身を追加する要素の元の中身をslotに反映することができます。Shadow DOMと一緒に使われることで効果が発動されるのでShadow DOMと合わせて紹介します。
<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="wvXQQqJ" data-editable="true" data-user="kokisakano" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/kokisakano/pen/wvXQQqJ">
  template03</a> by KokiSakano (<a href="https://codepen.io/kokisakano">@kokisakano</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

`template`では`slot`だった箇所がShadow Hostの元々の中身に置き換わっていることが確認できます。Shadow DOM化せずに行った場合は`slot`の箇所への置き換えが行われないことに注意して下さい。なお、slotに置き換えられた部分はShadow DOMのcssではなく、元のLight DOMのcssを参照します。
`slot`にname属性を設定することで複数の`slot`を利用することができます。埋め込むコンテンツのslot属性に`slot`のname属性に設定したものと同じ名前をつけることでお互いが紐づきます。
<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="LYrXXwp" data-editable="true" data-user="kokisakano" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/kokisakano/pen/LYrXXwp">
  template03</a> by KokiSakano (<a href="https://codepen.io/kokisakano">@kokisakano</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

埋め込むコンテンツの記述した順番ではなく、指定したslotに代入されていることが確認できます。また、Shadow Treeである`template`の中身はShadow DOM内のstyleによって青色の文字色になっていますが、slotの部分に外部から挿入されたものはLight　DOM内のstyleによって赤色の文字色になっています。

# まとめ
Web Componentsを利用するために必要なHTML Templateを学びました。この機能を用いて再利用可能なHTMLのテンプレートを準備すること、Shadow DOMになる前の中身を抜き出すことができるようになります。