とりあえずソースコードは次のようになります。
このソースコードで作るカスタムタグは最初のサンプルと同じです。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>WebContent Sample</title>
<template id="TmplTwoSlot">
<div>
<div>
<slot></slot>
</div>
<div>
<div class="inline-div">
<slot name="inner1"></slot>
</div>
<div class="inline-div">
<slot name="inner2"></slot>
</div>
</div>
</div>
<style>
.inline-div {
display: inline-block;
}
</style>
</template>
<script>
class TwoSlot extends HTMLElement {
constructor(){
super();
}
connectedCallback(){
let sr = this.attachShadow({mode: "open"});
const tmpl = document.getElementById("TmplTwoSlot");
const clone = document.importNode(tmpl.content, true);
sr.appendChild(clone);
}
}
customElements.define("two-slot", TwoSlot);
</script>
</head>
<body>
<two-slot id="TwoSlotSample">
<p slot="inner1" class="left">hoge</p>
<p slot="inner2" class="right">fuga</p>
<div class="main">
<h1>タイトル</h1>
<div>
これはメインのコンテンツです。
</div>
</div>
</two-slot>
</body>
</html>
最初のサンプルではTwoSlotクラスのtemplate()静的メソッドで作っていたHTMLを<template>に切り出した形になっています。
<template>タグの内容はページが読み込まれてもレンダリングされません。
MDNのドキュメントにも書いてありますが、JSを使用してインスタンス生成するためのテンプレート(コンテンツの断片)で、JSで動的生成しないなら意味のないタグです。
テンプレートを利用するために処理が変更になっています。
自身にattachShadow()するのは同じですが、テンプレート要素を取得し(36行目)、document.inportNode()でそれを複製して(37行目)、シャドウルートに追加しています。
つまり、シャドウルート以下に挿入する内容を<template>から取ってくる様に変更されたと言うわけです。
当然、最初のサンプルと同じになります。
hoge
fuga
WebComponentsを調べ始めて割と早い段階で<template>のことを読んでいました。と言うか、WebComponentsは少なくとも1回大きく変更されている様で、古いやり方(興味ある人はGoogle先生に聞いてみてください。Object.create()でHTMLElementを継承したオブジェクトを作成し、document.registerElement()で登録するやり方です。現在はこの方法は破棄されています)の記事がたくさん見つかるのですが、そこで<template>を使っていたのです。
その時に思ったのが、これはそんなに便利なのか?でした。
むしろ、最初のサンプルの様にすればJSに閉じるのでそっちの方が便利に思えたのです。テンプレート文字列を使えばHTMLはそのまま書けるし、変数埋め込みができる分そちらの方が便利に思えたわけです。
ですが、現在では<template>は非常に有効な機能だと思っています。その理由は次とその次で説明します。