とりあえずソースコードは次のようになります。
このソースコードで作るカスタムタグは最初のサンプルと同じです。
<!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>は非常に有効な機能だと思っています。その理由は次とその次で説明します。