From 44c48e6f6c8305e841c413bde7015269c328d423 Mon Sep 17 00:00:00 2001 From: Masahiro FUJIMOTO Date: Mon, 17 Jan 2022 01:41:11 +0900 Subject: 2021/10/26 時点の英語版に同期 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../using_templates_and_slots/index.md | 417 +++++++++------------ 1 file changed, 181 insertions(+), 236 deletions(-) (limited to 'files/ja') diff --git a/files/ja/web/web_components/using_templates_and_slots/index.md b/files/ja/web/web_components/using_templates_and_slots/index.md index 016ad83ce5..a43891ecac 100644 --- a/files/ja/web/web_components/using_templates_and_slots/index.md +++ b/files/ja/web/web_components/using_templates_and_slots/index.md @@ -1,35 +1,50 @@ --- -title: template と slot の使い方 +title: テンプレートとスロットの使用 slug: Web/Web_Components/Using_templates_and_slots +tags: + - Template + - ウェブコンポーネント + - シャドウ DOM + - slot + - スロット translation_of: Web/Web_Components/Using_templates_and_slots --- -
{{DefaultAPISidebar("Web Components")}}
+{{DefaultAPISidebar("Web Components")}} -

この記事では shadow DOM で使われる {{htmlelement("template")}} と {{htmlelement("slot")}} 要素の使い方を説明します。

+この記事では、{{htmlelement("template")}} と {{htmlelement("slot")}} 要素を使用して柔軟なテンプレートを作成し、それをウェブコンポーネントのシャドウ DOM を表示するために使用する方法について説明します。 -

テンプレートの真実

+## テンプレートの真実 -

あるWebページ上で同じ構造を繰り返し使用する必要がある場合、同じ実装を繰り返し書くよりも、テンプレートのようなものを作って利用する方が合理的でしょう。これは以前から可能でしたが、{{htmlelement("template")}} 要素より簡単に使えるようになりました。 この要素と中身は DOM 上ではレンダリングされませんが、JavaScript から参照することができます。

+ウェブページで同じマークアップ構造を繰り返し再利用する必要がある場合、同じ構造を何度も繰り返すよりも、何らかのテンプレートを使用する方が理にかなっています。 +これは以前から可能でしたが、HTML の {{htmlelement("template")}} 要素によって、かなり容易になりました(最近のブラウザーはよく対応しています)。 +この要素とその内容は DOM 内で描画されませんが、JavaScript を使って参照することは可能です。 -

以下の簡単なサンプルを見てみましょう。

+簡単な例を見てみましょう。 -
<template id="my-paragraph">
-  <p>My paragraph</p>
-</template>
+```html + +``` -

テンプレートの内部はページには表示されません。以下のコードのようにJavaScript を用いて参照を取り DOM に追加するとページ上に表示できます。

+これはページ上に表示されず、以下のようなコードで JavaScript で参照を取得し、 DOM に追加することで表示されます。 -
let template = document.getElementById('my-paragraph');
+```js
+let template = document.getElementById('my-paragraph');
 let templateContent = template.content;
-document.body.appendChild(templateContent);
+document.body.appendChild(templateContent); +``` -

つまらない例ですがすでに有用性は見えてきたでしょう。

+つまらない例ですが、すでに有用性は見えてきたでしょう。 -

Web Componentsを利用したテンプレートの使用

+## ウェブコンポーネントを用いたテンプレートの使用 -

テンプレートはそれ自身でも有用ですが web コンポーネントと共に使用することでより上手く使えます。テンプレートを shadow DOM として活用する web コンポーネントを <my-paragraph> と名付け定義しましょう。

+テンプレートはそれ自体でも便利ですが、ウェブコンポーネントと組み合わせるとさらに効果的です。 +テンプレートをシャドウ DOM の内容として使用するウェブコンポーネントを定義してみましょう。 +同様に `` と呼ぶことにします。 -
customElements.define('my-paragraph',
+```js
+customElements.define('my-paragraph',
   class extends HTMLElement {
     constructor() {
       super();
@@ -38,92 +53,104 @@ document.body.appendChild(templateContent);
const shadowRoot = this.attachShadow({mode: 'open'}) .appendChild(templateContent.cloneNode(true)); + } } -}) +); +``` -

ここで、テンプレートの内容を使用するために {{domxref("Node.cloneNode()")}} を使用してクローンしたものを shadow root に追加していることに注意してください。

+ここで、テンプレートの内容を使用するために {{domxref("Node.cloneNode()")}} メソッドを使用して複製したものをシャドウルートに追加していることに注意してください。 -

テンプレートの内容を shadow DOM に追加しているので、テンプレートの内部に {{htmlelement("style")}} 要素を用意しスタイルを含むことができます。このスタイルはカスタム要素の内部でカプセル化されます。これは通常の DOM に追加するだけでは正しく動きません。

+また、その内容をシャドウ DOM に追加しているため、テンプレート内のスタイル情報を {{htmlelement("style")}} 要素に含めることができ、それがカスタム要素内にカプセル化されます。 +これは、単に標準 DOM に追加しただけでは機能しません。 -

したがって、例えば

+したがって、例えば -
<template id="my-paragraph">
-  <style>
+```html
+
+```
+
+HTML 文書に次のように追加するだけで利用できるようになりました。
 
-

こうすれば HTML ドキュメントに以下を追加することで使用できます。

+```html + +``` -
<my-paragraph></my-paragraph>
-
+> **Note:** テンプレートはブラウザーの対応が進んでいます。 Shadow DOM API は既定で、 Firefox (バージョン 63 以降) 、Chrome、Opera、Safari、Edge (バージョン 79 以降) で対応しています。 -
-

注意: テンプレートはブラウザでよくサポートされています。Shadow DOM APIはデフォルトのFirefox (バージョン63以降) 、Chrome、OperaそしてSafariでサポートされています。Edgeでも現在開発が行われています。

-
+## スロットによる柔軟性の強化 -

スロットによる柔軟性の強化

+ここまではいいのですが、この要素はあまり柔軟ではありません。 +中には高々 1 つのテキストを表示できるだけなので、現時点では通常の段落よりも有用ではありません。 {{htmlelement("slot")}} 要素を使用することで、各要素インスタンスに異なるテキストを表示することを宣言的に行えるようにすることができます。 +これは {{htmlelement("template")}} よりも対応が限定されており、Chrome 53, Opera 40, Safari 10, Firefox 59, Edge 79 から利用可能です。 -

ここまでのサンプルでは高々1種類のテキストを表示できるのみで、普通の paragraph よりも使えません。{{htmlelement("slot")}} 要素を用いることで、各要素のインスタンスに異なるテキストを表示させることができます。{{htmlelement("slot")}}  は {{htmlelement("template")}} よりサポートが限られており、Chrome 53以降、Opera 40以降、Safari 10以降、Firefox 59以降で実装されていますが、Edge ではまだサポートされていません。slot はその name 属性で区別されており、template の中で任意のマークアップで slot の内容のデフォルト値を埋めることができます。

+スロットは `name` 属性で識別され、テンプレート内にプレイスホルダーを定義することができます。このプレースホルダーは、その要素がマークアップで使用されたときに、任意のマークアップフラグメントで埋められるようになります。 -

上記の例に slot を追加することを考えます。パラグラフの要素を以下のように書くことができます。

+ですから、この些細な例にスロットを追加したい場合、テンプレートの段落要素を次のように更新してください。 -
<p><slot name="my-text">デフォルトテキスト</slot></p>
+```html +

既定のテキスト

+``` -

slot の内容が定義されていない場合や、ブラウザが slot をサポートしていな場合は <my-paragraph> は fallback コンテンツを保持し、このサンプルの場合では "デフォルトテキスト" を表示させることになります。

+マークアップに要素が含まれるときにスロットの内容が定義されていない場合、またはブラウザーがスロットに対応していない場合、 `` はに単に代替内容である「既定のテキスト」が入ります。 -

内容を定義したい slot の名前を {{htmlattrxref("slot")}} 属性に設定した要素を <my-paragraph> の中に用意すると、その中身が slot の内容になります。中身は HTML 構造を持つ任意のもので埋めることができます。

+スロットの内容を定義するために、`` 要素の中に HTML 構造を入れ、 {{htmlattrxref("slot")}} 属性の値が埋めたいスロットの名前と同じになるようにします。前と同じように、これは好きなものを指定できます。 -
<my-paragraph>
-  <span slot="my-text">新しいテキストを代入します</span>
-</my-paragraph>
+```html + + 別なテキストを入れましょう。 + +``` -

以下のようにも設定できます。

+以下のようにも設定できます。 + +```html + +
    +
  • 別なテキストを入れましょう。
  • +
  • リストの中です。
  • +
+
+``` -
<my-paragraph>
-  <ul slot="my-text">
-    <li>新しいテキストを代入します</li>
-    <li>リストも代入できます</li>
-  </ul>
-</my-paragraph>
-
+> **Note:** スロットに挿入できるのは _Slotable_ な要素に限られます; 要素がスロットに挿入されたとき、_slotted_ と呼ばれます。 -
-

注意: スロットに挿入できるのは {{domxref("Slotable")}} な要素に限られます; 要素がスロットに挿入されたとき、slotted と呼ばれます。

-
+> **Note:** 無名の {{HTMLElement("slot")}} には、カスタム要素のトップレベルの子ノードのうち {{htmlattrxref("slot")}} 属性を持たないすべてのノードが入ります。これにはテキストノードも含まれます。 -

簡単なサンプルでの説明は以上です。他にも実装してみたい場合は、GitHub上のサンプルコードをご利用ください(実行例)。

+簡単な例での説明は以上です。 +もっと実行してみたい場合は、 [GitHub 上にあります](https://github.com/mdn/web-components-examples/tree/master/simple-template) ([ライブ実行版](https://mdn.github.io/web-components-examples/simple-template/)もあります)。 -

より踏み込んだ例

+

より踏み込んだ例

-

他の例もみてみましょう。

+記事の最後に、もう少し本格的なものを見てみましょう。 -

これからのコードは {{htmlelement("slot")}} を {{htmlelement("template")}} と共に使用する方法の例です。以下の2点を目指す JavaScript です。

+以下の一連のコードは、 {{HTMLElement("slot")}} を {{HTMLElement("template")}} と若干の JavaScript と組み合わせて使用する方法を示すコードスニペットです。 -
    -
  • shadow root の中で <element-details> 要素を slot を用いて作ること。
  • -
  • <element-details> 要素を、その shadow root と一緒にレンダリングされるように作ること。つまり、要素の内容が slots の中身に代入されるようになります。
  • -
+- **``** 要素を[名前付きスロット](/ja/docs/Web/HTML/Element/slot#named-slot)付きで[シャドウルート](/ja/docs/Web/API/ShadowRoot)の中に作成する +- **``** 要素を、文書内で使用されたとき、要素の内容とその[シャドウルート](/ja/docs/Web/API/ShadowRoot)の内容を組み合わせてレンダリングされるように設計します。つまり、要素の内容の断片は、その[シャドウルート](/ja/docs/Web/HTML/Element/slot#named-slot) の中で[名前付きスロット](/ja/docs/Web/API/ShadowRoot)を埋めるために使用されます。 -

{{htmlelement("slot")}} 要素は {{htmlelement("template")}} 要素なしで使用することが可能です。例えば、 {{HTMLElement("div")}} 要素の中で宣言しても Shadow DOM で使用した場合と同様にプレースホルダーとしての役割は果たします。しかし、{{HTMLElement("template")}} 要素の中で使用する方がより一般的で実用的です。

+なお、 {{HTMLElement("slot")}} 要素は技術的には、 {{HTMLElement("template")}} 要素なしで、例えば、通常の {{HTMLElement("div")}} 要素内で使うことも可能であり、それでもシャドウ DOM 内容に対して {{HTMLElement("slot")}} のプレースホルダー機能を活用することができますし、そうすれば、最初にテンプレート要素の `content` プロパティにアクセス(してそれを複製)する必要があるという小さなトラブルも実際に避けることができます。 +しかし、一般的には {{HTMLElement("template")}} 要素内にスロットを追加する方がより実用的です。なぜなら、既にレンダリングされた要素に基づいてパターンを定義する必要があることはほとんどないからです。 -

テンプレートを利用したコンテナの目的は {{HTMLElement("template")}} を使用することで意味的にわかりやすくすることです。さらに、{{HTMLElement("template")}} の中には {{HTMLElement("td")}} など直接追加して良い要素があり、これらは {{HTMLElement("div")}} 要素の中に追加された場合は消えます。

+また、まだレンダリングされていない場合でも、 {{HTMLElement("template")}} を使用することで、テンプレートとしてのコンテナーの目的がより意味的に明確になるはずです。また、 {{HTMLElement("template")}} には、 {{HTMLElement("td")}} のような、 {{HTMLElement("div")}} に追加すると消えてしまうような項目を直接追加することができます。 -
-

注意: element-detailsの完全なコードはここから見ることができます (実行例)。

-
+> **Note:** 完全な例は [element-details](https://github.com/mdn/web-components-examples/tree/master/element-details) で ([ライブ実行版](https://mdn.github.io/web-components-examples/element-details/)も) 参照することができます。 -

template をスロットと共に作る

+### template をスロットと共に作成 -

まず最初に{{htmlelement("template")}} 要素の中に {{htmlelement("slot")}} 要素を作成し、新しい "element-details-template" と名付けたフラグメントを作ります。

+まず最初に {{HTMLElement("slot")}} 要素を {{HTMLElement("template")}} 要素の中に作成し、[名前付きスロット](/ja/docs/Web/HTML/Element/slot#named-slot)を含んだ新しい "element-details-template" という[文書フラグメント](/ja/docs/Web/API/DocumentFragment)を作成します。 -
<template id="element-details-template">
-  <style>
+```html
+
+```
+
+この {{HTMLElement("template")}} 要素にはいくつかの特徴があります。
+
+- {{HTMLElement("template")}} には {{HTMLElement("style")}} 要素があり、 {{HTMLElement("template")}} が生成する文書の断片だけを対象とした CSS スタイルの集合を持ちます。
+- {{HTMLElement("template")}} は {{HTMLElement("slot")}} とその {{htmlattrxref("name", "slot")}} 属性を用いて、 3 つの[名前付きスロット](/ja/docs/Web/HTML/Element/slot#named-slot) を生成しています。
+
+  - ``
+  - ``
+  - ``
+
+- {{HTMLElement("template")}} には[名前付きスロット](/ja/docs/Web/HTML/Element/slot#named-slot)を {{HTMLElement("details")}} 要素の中に持ちます。
+
+### 新しい \ 要素を \