diff options
author | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:40:17 -0500 |
---|---|---|
committer | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:40:17 -0500 |
commit | 33058f2b292b3a581333bdfb21b8f671898c5060 (patch) | |
tree | 51c3e392513ec574331b2d3f85c394445ea803c6 /files/ja/web/web_components | |
parent | 8b66d724f7caf0157093fb09cfec8fbd0c6ad50a (diff) | |
download | translated-content-33058f2b292b3a581333bdfb21b8f671898c5060.tar.gz translated-content-33058f2b292b3a581333bdfb21b8f671898c5060.tar.bz2 translated-content-33058f2b292b3a581333bdfb21b8f671898c5060.zip |
initial commit
Diffstat (limited to 'files/ja/web/web_components')
-rw-r--r-- | files/ja/web/web_components/html_imports/index.html | 46 | ||||
-rw-r--r-- | files/ja/web/web_components/index.html | 218 | ||||
-rw-r--r-- | files/ja/web/web_components/status_in_firefox/index.html | 58 | ||||
-rw-r--r-- | files/ja/web/web_components/using_custom_elements/index.html | 305 | ||||
-rw-r--r-- | files/ja/web/web_components/using_shadow_dom/index.html | 218 | ||||
-rw-r--r-- | files/ja/web/web_components/using_templates_and_slots/index.html | 324 |
6 files changed, 1169 insertions, 0 deletions
diff --git a/files/ja/web/web_components/html_imports/index.html b/files/ja/web/web_components/html_imports/index.html new file mode 100644 index 0000000000..41d80f7a87 --- /dev/null +++ b/files/ja/web/web_components/html_imports/index.html @@ -0,0 +1,46 @@ +--- +title: HTML インポート +slug: Web/Web_Components/HTML_Imports +translation_of: Web/Web_Components/HTML_Imports +--- +<p>{{DefaultAPISidebar("Web Components")}}</p> + +<div class="blockIndicator obsolete"> +<p><strong>Google Chrome 73 で廃止</strong><br> + この機能は廃止されました。まだいくつかのブラウザーで動作するかもしれませんが、いつ削除されてもおかしくないので、使わないようにしましょう。</p> +</div> + +<div class="blockIndicator warning"> +<p>Firefox はこの形式の <em>HTML インポート</em> は提供していません。詳細は<a href="https://hacks.mozilla.org/2015/06/the-state-of-web-components/">状況更新</a>を参照してください。標準化への同意が集まるか、代替機構が発表されるまで、Google の <code><a href="https://github.com/webcomponents/webcomponentsjs">webcomponents.js</a></code> などのポリフィルを使用することができます。</p> +</div> + +<p><em>HTML インポート</em> は <a href="/ja/docs/Web/Web_Components">Web Components</a> のパッケージング機構として使用されることを意図していますが、単独で使用することもできます。</p> + +<p>以下のように、HTML 文書中で <a href="/ja/docs/Web/HTML/Element/link"><code><link></code></a> タグを使用してインポートします。</p> + +<pre><link rel="import" href="myfile.html"></pre> + +<p>リンク種別 <code>import</code> は新設です。</p> + +<h2 id="仕様">仕様</h2> + +<table class="spec-table standard-table"> + <tbody> + <tr> + <th scope="col">仕様</th> + <th scope="col">状態</th> + <th scope="col">備考</th> + </tr> + <tr> + <td>{{SpecName("HTML Imports")}}</td> + <td>{{Spec2("HTML Imports")}}</td> + <td>初回定義。</td> + </tr> + </tbody> +</table> + +<h2 id="ブラウザーの互換性">ブラウザーの互換性</h2> + +<p class="hidden">The compatibility table in this page is generated from structured data. If you'd like to contribute to the data, please check out <a href="https://github.com/mdn/browser-compat-data">https://github.com/mdn/browser-compat-data</a> and send us a pull request.</p> + +<p>{{Compat("html.elements.link.rel.import")}}</p> diff --git a/files/ja/web/web_components/index.html b/files/ja/web/web_components/index.html new file mode 100644 index 0000000000..79f4bbbe10 --- /dev/null +++ b/files/ja/web/web_components/index.html @@ -0,0 +1,218 @@ +--- +title: Web Components +slug: Web/Web_Components +tags: + - Landing + - NeedsTranslation + - TopicStub + - Web Components +translation_of: Web/Web_Components +--- +<p>{{DefaultAPISidebar("Web Components")}}</p> + +<div class="summary"> +<p>Web Components は、再利用可能なカスタム要素を作成し、ウェブアプリの中で利用するための、一連のテクノロジーです。コードの他の部分から独立した、カプセル化された機能を使って実現します。 </p> +</div> + +<h2 id="概念と使用法">概念と使用法</h2> + + + +<p>開発者ならご存知でしょうが、可能な限りコードを再利用することは良い考えです。しかしこれは、以前から、カスタムのマークアップ構造にとって、それほど簡単なことではありませんでした。複雑な HTML (と一連のスタイルやスクリプト) を考えてみて下さい。ときに、カスタム UI の制御をレンダリングするために、コードを書かなければなりません。それに、注意していないと、それらの制御をどう使い回すかで、ページが複雑なものになってしまいます。</p> + +<p>Web Components は、上記の問題の解決を目指しています。 Web Components は、3 つの主要な技術からなり、それらを組み合わせて、多目的なカスタム要素を作成します。カプセル化された機能を使うことで、コードの重複を恐れることなく、どこでも再利用することができます。</p> + +<ul> + <li><strong>カスタム要素:</strong> カスタム要素とその動作を定義するための、一連の JavaScript API です。以降、ユーザーインターフェースの中で好きなだけ使用することができます。</li> + <li><strong>Shadow DOM:</strong> カプセル化された "Shadow" DOM ツリーを要素に紐付け、関連する機能を制御するための、一連の JavaScript API です。 Shadow DOM ツリーは、メインドキュメントの DOM とは別にレンダリングされます。こうして、要素の機能を公開せずに済み、ドキュメントの他の部分との重複を恐れることなく、スクリプト化やスタイル化できます。</li> + <li><strong>HTML テンプレート:</strong> {{HTMLElement("template")}} と {{HTMLElement("slot")}} 要素によって、レンダリングされたページ内に表示されないマークアップのテンプレートを書くことができます。カスタム要素の構造体の基礎として、それらを何度も再利用できます。</li> +</ul> + +<p>Web Component を実装する基本的な流れは、以下に挙げてある通りです。</p> + +<ol> + <li>Web Component の機能を明示したクラスもしくは関数を作成します。クラスを使用するなら、ECMAScript 2015 のクラスの文法に従って下さい。 (詳細は<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes">クラス</a>を参照して下さい。)</li> + <li>新しく作成したカスタム要素を登録します。{{domxref("CustomElementRegistry.define()")}} メソッドに、要素の名前、機能が明示されているクラスもしくは関数、またオプションでどの要素を継承するかを渡して下さい。</li> + <li>必要なら、{{domxref("Element.attachShadow()")}} メソッドを使って、Shadow DOM をカスタム要素に紐付けます。通常の DOM メソッドを使って、子要素やイベントリスナーなどをShadow DOM に追加して下さい。</li> + <li>必要なら、{{htmlelement("template")}} と {{htmlelement("slot")}} を使って、HTML テンプレートを定義します。通常の DOM メソッドを再度使って、テンプレートをクローンし、Shadow DOM に紐付けてください。</li> + <li>ページ内のお好きな場所で、通常の HTML 要素のように、カスタム要素を使って下さい。</li> +</ol> + +<h2 id="チュートリアル">チュートリアル</h2> + +<dl> + <dt><a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements">カスタム要素を使ってみよう</a></dt> + <dd>単純な Web Component を作成するために、カスタム要素の機能の使い方を紹介したガイドラインです。それ以外にも、ライフサイクルコールバックやその他の高度な機能の中を覗いていきます。</dd> + <dt><a href="https://developer.mozilla.org/ja/docs/Web/Web_Components/Using_shadow_DOM">Shadow DOM を使ってみよう</a></dt> + <dd>Shadow DOM の基礎を眺めるガイドラインです。 Shadow DOM を要素にどう紐付けるか、Shadow DOM ツリーにどう追加するか、どうスタイルするかなどを紹介しています。</dd> + <dt><a href="https://developer.mozilla.org/ja/docs/Web/Web_Components/Using_templates_and_slots">テンプレートとスロットを使ってみよう</a></dt> + <dd>{{htmlelement("template")}} と {{htmlelement("slot")}} 要素を使って、再利用可能な HTML 構造体の定義と使用方法を紹介したガイドラインです。 </dd> +</dl> + +<h2 id="リファレンス">リファレンス</h2> + +<h3 id="カスタム要素">カスタム要素</h3> + +<dl> + <dt>{{domxref("CustomElementRegistry")}}</dt> + <dd>カスタム要素に関わる機能が含まれています。中でも注目すべきは、 {{domxref("CustomElementRegistry.define()")}} メソッドで、新しいカスタム要素を登録するために用います。それにより、カスタム要素をドキュメント内で使用できるようになります。</dd> + <dt>{{domxref("Window.customElements")}}</dt> + <dd><code>CustomElementRegistry</code> オブジェクトへの参照を返します。</dd> + <dt><a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements#Using_the_lifecycle_callbacks">Life cycle callbacks</a></dt> + <dd>カスタム要素のクラス定義の中で定義された特別なコールバック関数で、挙動に影響を与えます。 + <ul> + <li><code>connectedCallback</code>: カスタム要素がドキュメントの DOM に初めて接続したときに呼び出されます。</li> + <li><code>disconnectedCallback</code>: カスタム要素がドキュメントの DOM から切断されたときに呼び出されます。</li> + <li><code>adoptedCallback</code>: カスタム要素が新しいドキュメントに移動したときに呼び出されます。</li> + <li><code>attributeChangedCallback</code>: カスタム要素の属性のひとつが追加、削除、もしくは変更されたときに呼び出されます。</li> + </ul> + </dd> + <dd> + <ul> + </ul> + </dd> +</dl> + +<dl> + <dt>カスタムビルトイン要素を作成するための拡張機能</dt> + <dd> + <ul> + <li>{{htmlattrxref("is")}} グローバル HTML 属性: 標準の HTML 要素が、カスタムビルトイン要素のように振る舞うべきかを指定できます。</li> + <li>{{domxref("Document.createElement()")}} メソッドの "is" オプション: カスタムビルトイン要素のように振る舞う標準の HTML 要素のインスタンスを作成できます。</li> + </ul> + </dd> + <dt>CSS の擬似クラス</dt> + <dd>カスタム要素に関連する擬似クラス: + <ul> + <li>{{cssxref(":defined")}}: ビルトイン要素と <code>CustomElementRegistry.define()</code> で定義されるカスタム要素を含む、あらゆる定義済みの要素にマッチします。</li> + <li>{{cssxref(":host")}}: 使われている CSS を含む、<a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM">Shadow DOM</a> のシャドーホストを選択します。</li> + <li>{{cssxref(":host()")}}: 使われている CSS を含む、<a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM">Shadow DOM</a> のシャドーホストを選択します。 (Shadow DOM の内側からカスタム要素を選択することができます。) ただし、関数のパラメータとして渡されるセレクタがシャドーホストに一致している場合に限ります。</li> + <li>{{cssxref(":host-context()")}}: 使われている CSS を含む、<a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM">Shadow DOM</a> のシャドーホストを選択します。 (Shadow DOM の内側からカスタム要素を選択することができます。) ただし、関数のパラメータとして渡されるセレクタが DOM 階層内のシャドーホストの先祖要素に一致している場合に限ります。</li> + </ul> + </dd> +</dl> + +<h3 id="Shadow_DOM">Shadow DOM</h3> + +<dl> + <dt>{{domxref("ShadowRoot")}}</dt> + <dd>Represents the root node of a shadow DOM subtree.</dd> + <dt>{{domxref("DocumentOrShadowRoot")}}</dt> + <dd>A mixin defining features that are available across document and shadow roots.</dd> + <dt>{{domxref("Element")}} extensions</dt> + <dd>Extensions to the <code>Element</code> interface related to shadow DOM: + <ul> + <li>The {{domxref("Element.attachShadow()")}} method attaches a shadow DOM tree to the specified element.</li> + <li>The {{domxref("Element.shadowRoot")}} property returns the shadow root attached to the specified element, or <code>null</code> if there is no shadow root attached.</li> + </ul> + </dd> + <dt>Relevant {{domxref("Node")}} additions</dt> + <dd>Additions to the <code>Node</code> interface relevant to shadow DOM: + <ul> + <li>The {{domxref("Node.getRootNode()")}} method returns the context object's root, which optionally includes the shadow root if it is available.</li> + <li>The {{domxref("Node.isConnected")}} property returns a boolean indicating whether or not the Node is connected (directly or indirectly) to the context object, e.g. the {{domxref("Document")}} object in the case of the normal DOM, or the {{domxref("ShadowRoot")}} in the case of a shadow DOM.</li> + </ul> + </dd> + <dt>{{domxref("Event")}} extensions</dt> + <dd>Extensions to the <code>Event</code> interface related to shadow DOM: + <ul> + <li>{{domxref("Event.composed")}}: Returns a {{jsxref("Boolean")}} which indicates whether the event will propagate across the shadow DOM boundary into the standard DOM (<code>true</code>), or not (<code>false</code>).</li> + <li>{{domxref("Event.composedPath")}}: Returns the event’s path (objects on which listeners will be invoked). This does not include nodes in shadow trees if the shadow root was created with {{domxref("ShadowRoot.mode")}} closed.</li> + </ul> + </dd> +</dl> + +<h3 id="HTML_templates">HTML templates</h3> + +<dl> + <dt>{{htmlelement("template")}}</dt> + <dd>Contains an HTML fragment that is not rendered when a containing document is initially loaded, but can be displayed at runtime using JavaScript, mainly used as the basis of custom element structures. The associated DOM interface is {{domxref("HTMLTemplateElement")}}.</dd> + <dt>{{htmlelement("slot")}}</dt> + <dd>A placeholder inside a web component that you can fill with your own markup, which lets you create separate DOM trees and present them together. The associated DOM interface is {{domxref("HTMLSlotElement")}}.</dd> + <dt>The <code><a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/slot">slot</a></code> global HTML attribute</dt> + <dd>Assigns a slot in a shadow DOM shadow tree to an element.</dd> + <dt>{{domxref("Slotable")}}</dt> + <dd>A mixin implemented by both {{domxref("Element")}} and {{domxref("Text")}} nodes, defining features that allow them to become the contents of an {{htmlelement("slot")}} element. The mixin defines one attribute, {{domxref("Slotable.assignedSlot")}}, which returns a reference to the slot the node is inserted in.</dd> +</dl> + +<dl> + <dt>{{domxref("Element")}} extensions</dt> + <dd>Extensions to the <code>Element</code> interface related to slots: + <ul> + <li>{{domxref("Element.slot")}}: Returns the name of the shadow DOM slot attached to the element.</li> + </ul> + </dd> + <dt>CSS pseudo-elements</dt> + <dd>Pseudo-elements relating specifically to slots: + <ul> + <li>{{cssxref("::slotted")}}: Matches any content that is inserted into a slot.</li> + </ul> + </dd> + <dt>The {{event("slotchange")}} event</dt> + <dd>Fired on an {{domxref("HTMLSlotElement")}} instance ({{htmlelement("slot")}} element) when the node(s) contained in that slot change.</dd> +</dl> + +<h2 id="例">例</h2> + +<p><a href="https://github.com/mdn/web-components-examples">web-components-examples</a> の GitHub レポジトリに、いくつかの例を用意してあります。時間とともに、より多くの例が追加されることでしょう。</p> + +<h2 id="Specifications" name="Specifications">仕様</h2> + +<table class="standard-table"> + <tbody> + <tr> + <th scope="col">仕様</th> + <th scope="col">ステータス</th> + <th scope="col">コメント</th> + </tr> + <tr> + <td>{{SpecName("HTML WHATWG","scripting.html#the-template-element","<template> element")}}</td> + <td>{{Spec2('HTML WHATWG')}}</td> + <td>{{HTMLElement("template")}} の定義です。</td> + </tr> + <tr> + <td>{{SpecName("HTML WHATWG","custom-elements.html#custom-elements","custom elements")}}</td> + <td>{{Spec2('HTML WHATWG')}}</td> + <td><a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements">HTML Custom Elements</a> の定義です。</td> + </tr> + <tr> + <td>{{SpecName("DOM WHATWG","#shadow-trees","shadow trees")}}</td> + <td>{{Spec2('DOM WHATWG')}}</td> + <td><a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM">Shadow DOM</a> の定義です。</td> + </tr> + <tr> + <td>{{SpecName("HTML Imports", "", "")}}</td> + <td>{{Spec2("HTML Imports")}}</td> + <td><a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components/HTML_Imports">HTML Imports</a> の最初の定義です。</td> + </tr> + <tr> + <td>{{SpecName("Shadow DOM", "", "")}}</td> + <td>{{Spec2("Shadow DOM")}}</td> + <td><a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM">Shadow DOM</a> の最初の定義です。</td> + </tr> + </tbody> +</table> + +<h2 id="ブラウザのサポート">ブラウザのサポート</h2> + + + +<p>一般に、</p> + +<ul> + <li>Web Components は、Firefox (バージョン 63、現在のところ <a href="https://www.mozilla.org/en-GB/firefox/developer/">開発者エディション</a>)、Chrome そして Opera でサポートされています。 </li> + <li>Safari では、いくつかの Web Components の機能がサポートされていますが、上記のブラウザほどではありません。</li> + <li>Edge では、現在実装中です。</li> +</ul> + +<p>特定の機能のブラウザでの実装状況は、上記のページを調べるようにして下さい。</p> + + + +<h2 id="参考">参考</h2> + +<ul> + <li><a href="https://www.webcomponents.org/">webcomponents.org</a> — site featuring web components examples, tutorials, and other information.</li> + <li><a href="https://www.polymer-project.org/">Polymer</a> — Google's web components framework — a set of polyfills, enhancements, and examples. Currently the easiest way to use web components cross-browser.</li> + <li><a href="https://github.com/slimjs/slim.js">Slim.js</a> — Open source web components library — a high-performant library for rapid and easy component authoring; extensible and pluggable and cross-framework compatible. </li> +</ul> diff --git a/files/ja/web/web_components/status_in_firefox/index.html b/files/ja/web/web_components/status_in_firefox/index.html new file mode 100644 index 0000000000..0fa1b2248b --- /dev/null +++ b/files/ja/web/web_components/status_in_firefox/index.html @@ -0,0 +1,58 @@ +--- +title: Firefox での Web Components のサポート状況 +slug: Web/Web_Components/Status_in_Firefox +tags: + - API + - Experimental + - Firefox + - Guide + - Web Components + - status +translation_of: Web/Web_Components/Status_in_Firefox +--- +<p>{{DefaultAPISidebar("Web Components")}}{{SeeCompatTable}}</p> + +<p><a href="/docs/Web/Web_Components">Web Components</a> は、とても新しい技術で、ブラウザ実装者や Web 開発者が実際に利用した経験を集めて仕様を考案しています。実装状況は変化しやすく、次々と進化していきます。この記事は、Firefox や Firefox OS で使用されている <a href="/docs/Mozilla/Gecko">Gecko</a> での実装状況の一覧を示します。</p> + +<div class="blob instapaper_body" id="readme"> +<article class="markdown-body entry-content"> +<h2 id="ネイティブサポート">ネイティブサポート</h2> + +<p>Firefox と Firefox OS では、以下の機能が実装されており、デフォルトで有効です:</p> + +<ul> + <li>{{HTMLElement("template")}}</li> +</ul> + +<h2 id="今後実装予定の機能">今後実装予定の機能</h2> + +<ul> + <li>新しい同意に基づいた <a href="/docs/Web/Web_Components/Shadow_DOM">Shadow DOM</a> の実装は、2016 年 Q1 にリリース予定です。<a href="https://annevankesteren.nl/2015/07/shadow-dom-custom-elements-update">Anne</a> と <a href="https://hacks.mozilla.org/2015/06/the-state-of-web-components/">Wilson</a> のブログ投稿に詳細が記述されています。しかし、まだ仕様について <a href="https://github.com/w3c/webcomponents/labels/shadow-dom">多くの議論や課題</a> があり、すべてのブラウザへの実装は将来となるでしょう。</li> + <li><strong>Custom elements</strong> は、最初からやり直しで、ECMAScript 6 の文法を使用してリビルドする計画 (つまり、より少ないプロトタイプを基に作成) です。Apple の Ryosuke Niwa が、実装をいくつか具体化しています。 + <ul> + <li>古い文法は、しばらくの間、新しい文法と共に Chrome で動作するでしょう (例えば、{{domxref("Element.attachShadow()")}} に対して {{domxref("Element.createShadowRoot()")}})、しかし、Firefox ではネイティブでは動作しないでしょう。</li> + </ul> + </li> + <li>これらの問題について、<a href="https://github.com/w3c/WebPlatformWG/blob/gh-pages/meetings/29janWC.md">2016 年 1 月の会議</a> でベンダが議論するでしょう。</li> +</ul> + +<h2 id="放棄された機能">放棄された機能</h2> + +<p>これらの機能は、実装の検討がされており、実験的に実装されていたものもあります。今後は改良もされず、削除されるでしょう。</p> + +<ul> + <li><strong>HTML imports</strong> の使用は、ES6 モジュールで開発者が何ができるかを確認することは、待って欲しいです (まだ実装されていません。{{bug(568953)}} をご覧ください)。Firefox から削除される予定の未完了の import の実装がありました。</li> +</ul> + +<h2 id="Firefox_でポリフィルを使用する">Firefox でポリフィルを使用する</h2> + +<p>Firefox でポリフィルを使用する際に考慮すべき注意事項があります:</p> + +<ul> + <li><code>about:config</code> の {{pref("dom.webcomponents.enabled")}} 設定を <code>true</code> に変更して Firefox で Web Components を有効にすると、完全でないネイティブ実装が動き始め、ポリフィルが混乱する可能性があります。</li> + <li><a href="https://github.com/webcomponents/webcomponentsjs">webcomponents.js</a> ポリフィルを使用した Shadow DOM のポリフィルは、スタイルをカプセル化できません。そのため、スタイルは bleed through でしょう。ポリフィルを使用して構築されたサイトは、ネイティブの Shadow DOM を <strong>サポートした</strong> 環境と異なる見た目になることに注意してください。</li> + <li>Shadow DOM のポリフィルは、機能にフックするために DOM 要素のプロトタイプをリライトするため、とても動作が遅いです (ポリフィルというよりポリリプレイスです!)。</li> + <li>Shadow DOM を使用する必要がない場合、webcomponents.js ポリフィルの <a href="https://github.com/webcomponents/webcomponentsjs">webcomponents-lite.js</a> バージョンを使用することをお勧めします。このバージョンは、Shadow DOM を使用しないポリフィルです。</li> +</ul> +</article> +</div> diff --git a/files/ja/web/web_components/using_custom_elements/index.html b/files/ja/web/web_components/using_custom_elements/index.html new file mode 100644 index 0000000000..c19f2f73c9 --- /dev/null +++ b/files/ja/web/web_components/using_custom_elements/index.html @@ -0,0 +1,305 @@ +--- +title: Using custom elements +slug: Web/Web_Components/Using_custom_elements +tags: + - Classes + - Guide + - HTML + - Web Components + - autonomous + - custom elements + - customized +translation_of: Web/Web_Components/Using_custom_elements +--- +<div>{{DefaultAPISidebar("Web Components")}}</div> + +<p class="summary">Webコンポーネント標準の重要な特徴の一つはカスタム要素を作れることです。それはページの機能を提供する長くネストした要素のバッチではなく、HTMLページ上で機能をカプセル化します。<br> + この記事はカスタム要素APIの使い方を紹介します。</p> + +<div class="note"> +<p><strong>注</strong>: カスタム要素をデフォルトでサポートするのは Firefox, Chrome, と Edge (76)です。Opera と Safari は今のところ、自律カスタム要素のみサポートしています。</p> +</div> + +<h2 id="High-level_view" name="High-level_view">High-level view</h2> + +<p>Webドキュメント上でカスタム要素をコントロールするのは {{domxref("CustomElementRegistry")}} オブジェクトです。 — このオブジェクトはページへのカスタム要素を登録したり、どんなカスタム要素が登録されているのかを返すなどの操作を行えます。</p> + +<p>ページにカスタム要素を登録するには, {{domxref("CustomElementRegistry.define()")}} メソッドを使います。次の引数を取ることができます:</p> + +<ul> + <li>エレメントの名前を表す {{domxref("DOMString")}} 。 カスタム要素の名前には <a href="https://stackoverflow.com/questions/22545621/do-custom-elements-require-a-dash-in-their-name">ダッシュを使う必要があります。</a>; 一つの単語の名前をつけられません。</li> + <li>要素の振る舞いを定義した <a href="/ja/docs/Web/JavaScript/Reference/Classes">クラス</a> オブジェクト。</li> + <li>オプションで, <code>extends</code>属性を含むオプションオブジェクト。組み込み要素をを継承する場合にはそれを指定します。</li> +</ul> + +<p>例えば、次の様に <a href="https://mdn.github.io/web-components-examples/word-count-web-component/">word-count 要素</a> を定義できます:</p> + +<pre class="brush: js">customElements.define('word-count', WordCount, { extends: 'p' });</pre> + +<p><code>word-count</code>要素は <code>WordCount</code>クラスのオブジェクトで {{htmlelement("p")}}要素を拡張します。</p> + +<p>カスタム要素のクラスオブジェクトは ES 2015 のクラスシンタックスで実装します。例えば、<code>WordCount</code> 次の様になります:</p> + +<pre class="brush: js">class WordCount extends HTMLParagraphElement { + constructor() { + // Always call super first in constructor + super(); + + // Element functionality written in here + + ... + } +}</pre> + +<p>これはごく簡単な例ですが、ここでできることはもっとあります。クラスの中でライフサイクルコールバックを定義することができ、要素のライフサイクルの特定のポイントで実行されます。例えば、<code>connectedCallback</code> はドキュメント接続要素にカスタム要素が追加されるたびに実行されます。一方 <code>attributeChangedCallback</code> はカスタム要素に属性が追加、削除、変更される時に実行されます。</p> + +<p>{{anch("Using the lifecycle callbacks")}} でこれらについてもっと学ぶことができます。.</p> + +<p>カスタム要素には2つのタイプがあります:</p> + +<ul> + <li>スタンドアロンの<strong>自律カスタム要素</strong> — 標準のHTML要素を継承していません。文字通りHTML要素としてページで使います。例えば、<code><popup-info></code> あるいは <code>document.createElement("popup-info")</code>の様に。</li> + <li>基礎とするHTML要素を継承する<strong>カスタマイズされた組み込み要素</strong>。 これらを作るために、どの要素を拡張するのかを(上の例で示したように)指定します。そして、 基本要素を書き出して使いますが、 {{htmlattrxref("is")}}属性 (またはプロパティ)でカスタム要素の名前を指定します。. 例えば、<code><p is="word-count"><font face="Arial, x-locale-body, sans-serif"><span style="background-color: #ffffff;"> あるいは</span></font></code><code>document.createElement("p", { is: "word-count" })</code>の様に。</li> +</ul> + +<h2 id="Working_through_some_simple_examples" name="Working_through_some_simple_examples">簡単な例と実践</h2> + +<p>ここで、どのようにカスタム要素をを作るのかを詳細に説明するために簡単な例を見てみましょう。</p> + +<h3 id="Autonomous_custom_elements" name="Autonomous_custom_elements">自律カスタム要素</h3> + +<p>自律カスタム要素の例を見てみましょう — <code><a href="https://github.com/mdn/web-components-examples/tree/master/popup-info-box-web-component"><popup-info-box></a></code> ( <a href="https://mdn.github.io/web-components-examples/popup-info-box-web-component/">実例</a>参照). これは画像とテキストを受け取り、ページにアイコンを埋め込みます。アイコンにフォーカスすると、ポップアップする情報ボックスにテキストを表示してコンテキスト内の情報を更に提供します。</p> + +<p>最初に{{domxref("HTMLElement")}}を継承して <code>PopUpInfo</code>,というクラスを定義します。 自律カスタム要素はほぼいつも <code>HTMLElement</code>を継承します。</p> + +<pre class="brush: js">class PopUpInfo extends HTMLElement { + constructor() { + // Always call super first in constructor + super(); + + // write element functionality in here + + ... + } +}</pre> + +<p>前述のコードスニペットはクラスの <code><a href="/ja/docs/Web/JavaScript/Reference/Classes/constructor">constructor()</a></code> の定義を含んでおり、常に <code><a href="/ja/docs/Web/JavaScript/Reference/Operators/super">super()</a></code> を最初に呼び出します。これにより正しいプロタイプチェーンが確立されます。</p> + +<p>コンストラクタ内で、インスタンス化された時に要素が持っているすべての機能を定義します。この例ではカスタム要素にshadowルートをアタッチしています。DOM操作を行い、要素内部の shadow DOM構造を作ります。—DOM構造はshadowルートにアタッチされます— そして最後にスタイルを適用するためにCSSをshadowルートにアタッチします。</p> + +<pre class="brush: js">// Create a shadow root +var shadow = this.attachShadow({mode: 'open'}); + +// Create spans +var wrapper = document.createElement('span'); +wrapper.setAttribute('class','wrapper'); +var icon = document.createElement('span'); +icon.setAttribute('class','icon'); +icon.setAttribute('tabindex', 0); +var info = document.createElement('span'); +info.setAttribute('class','info'); + +// Take attribute content and put it inside the info span +var text = this.getAttribute('text'); +info.textContent = text; + +// Insert icon +var imgUrl; +if(this.hasAttribute('img')) { + imgUrl = this.getAttribute('img'); +} else { + imgUrl = 'img/default.png'; +} +var img = document.createElement('img'); +img.src = imgUrl; +icon.appendChild(img); + +// Create some CSS to apply to the shadow dom +var style = document.createElement('style'); + +style.textContent = '.wrapper {' + +// CSS truncated for brevity + +// attach the created elements to the shadow dom + +shadow.appendChild(style); +shadow.appendChild(wrapper); +wrapper.appendChild(icon); +wrapper.appendChild(info);</pre> + +<p>最後に、カスタム要素を <code>CustomElementRegistry</code> に登録します。前述の <code>define()</code> を使用して、パラメーターで要素名とその機能を定義するクラス名を指定します:</p> + +<pre class="brush: js">customElements.define('popup-info', PopUpInfo);</pre> + +<p>これによってページで使えるようになりました。HTML中で下記のように使用することができます。</p> + +<pre class="brush: html"><popup-info img="img/alt.png" text="Your card validation code (CVC) + is an extra security feature — it is the last 3 or 4 numbers on the + back of your card."></popup-info></pre> + +<div class="note"> +<p><strong>注</strong>: こちらで <a href="https://github.com/mdn/web-components-examples/blob/master/popup-info-box-web-component/main.js">完全なソースコード</a> を見ることができます。</p> +</div> + +<div class="blockIndicator note"> +<p><strong>注</strong>: カスタム要素が機能するためには、DOMの解析を終えた後にカスタム要素を登録するスクリプトが読み込まれる必要があることに注意してください。これは <code><script></code> 要素を <code><body></code> 要素内の最下部に配置する、または <code><script></code> 要素に <code>defer</code> 属性を加えることで解決します。</p> +</div> + +<h3 id="Customized_built-in_elements" name="Customized_built-in_elements">内部スタイル 対 外部スタイル</h3> + +<p>上記の例では {{htmlelement("style")}} 要素を用いてShadow DOMにスタイルを適用しました。しかし、{{htmlelement("link")}} 要素から外部のスタイルシートを参照することも可能です。</p> + +<p>例えば、<a href="https://mdn.github.io/web-components-examples/popup-info-box-external-stylesheet/">popup-info-box-external-stylesheet</a> のコードを少し見てみましょう(<a href="https://github.com/mdn/web-components-examples/blob/master/popup-info-box-external-stylesheet/main.js">ソースコード</a>)。</p> + +<pre class="brush: js">// Apply external styles to the shadow dom +const linkElem = document.createElement('link'); +linkElem.setAttribute('rel', 'stylesheet'); +linkElem.setAttribute('href', 'style.css'); + +// Attach the created element to the shadow dom +shadow.appendChild(linkElem); +</pre> + +<p>この手法が特に大規模なスタイルシートで推奨されます。これによって、綺麗で、より共有しやすい効率の良いコードになります。</p> + +<h3 id="Customized_built-in_elements" name="Customized_built-in_elements">カスタマイズされたビルトイン要素</h3> + +<p>ここで、もう1つのビルトイン要素の例を見てみましょう — <a href="https://github.com/mdn/web-components-examples/tree/master/expanding-list-web-component">expanding-list</a> (<a href="https://mdn.github.io/web-components-examples/expanding-list-web-component/">デモはこちら</a>) 。 これにより番号なしリストが展開・縮小するメニューになります。<br> + <br> + まず始めに、これまでと同様の規則でクラス要素を定義します。</p> + +<pre class="brush: js">class ExpandingList extends HTMLUListElement { + constructor() { + // Always call super first in constructor + super(); + + // write element functionality in here + + ... + } +}</pre> + +<p>ここでは要素の詳細な機能については説明しませんが、ソースコードからどのように動作するのかチェックすることができます。これまでと唯一違う点は {{domxref("HTMLElement")}} ではなく、 {{domxref("HTMLUListElement")}} インターフェースを拡張していることです。そのため、独立した要素ではなく、 {{htmlelement("ul")}} 要素の特徴を備えた上に、私たちが定義した機能を持っています。これこそが自律カスタム要素ではなくカスタマイズされたビルトイン要素である理由です。<br> + <br> + 次に、以前と同様に <code>define()</code> を用いて要素を登録するのですが、今回はこのカスタム要素がどの要素から継承したのかという情報をオプションとして渡しています。</p> + +<pre class="brush: js">customElements.define('expanding-list', ExpandingList, { extends: "ul" });</pre> + +<p>Webドキュメント内でビルトイン要素を使用する場合とはやや異なります。</p> + +<pre class="brush: html"><ul is="expanding-list"> + + ... + +</ul></pre> + +<p>通常のように <code><ul></code> を使用していますが、カスタム要素の名前が <code>is</code> 属性で指定されています。</p> + +<div class="note"> +<p><strong>注</strong>: もう一度述べますが、こちらで <a href="https://github.com/mdn/web-components-examples/blob/master/popup-info-box-web-component/main.js">完全なソースコード</a> を見ることができます。</p> +</div> + +<h2 id="Using_the_lifecycle_callbacks" name="Using_the_lifecycle_callbacks">ライフサイクルコールバックの使用</h2> + +<p>カスタム要素のクラス定義内にいくつかの異なるコールバックを定義できます。これらのコールバックは、要素のライフサイクルのさまざまな時点で起動します。</p> + +<ul> + <li><code>connectedCallback</code>: 呼び出されるたびに、カスタム要素がドキュメントに接続された要素に追加されます。これは、ノードが移動されるたびに発生し、要素のコンテンツが完全に解析される前に発生する場合があります。 + + <div class="note"> + <p><strong>注</strong>: エレメントが接続されなくなったら<code>connectedCallback</code> を呼び出すことができます, {{domxref("Node.isConnected")}} を使用して確認してください.</p> + </div> + </li> + <li><code>disconnectedCallback</code>: カスタム要素がドキュメントのDOMから切断されるたびに呼び出されます。</li> + <li><code>adoptedCallback</code>: カスタム要素が新しいドキュメントに移動するたびに呼び出されます。</li> + <li><code>attributeChangedCallback</code>: カスタム要素の属性の1つが追加、削除、または変更されるたびに呼び出されます。変更を通知する属性は、 <code>static get observedAttributes()</code> メソッドで指定されます</li> +</ul> + +<p>使用中のこれらの例を見てみましょう。以下のコードは、<a href="https://github.com/mdn/web-components-examples/tree/master/life-cycle-callbacks">ライフサイクルコールバック</a>の例から取ったものです(<a href="https://mdn.github.io/web-components-examples/life-cycle-callbacks/">ライブ実行を参照</a>)。これは、ページ上に固定サイズの色付きの正方形を生成する単純な例です。カスタム要素は次のようになります。</p> + +<pre class="brush: html"><custom-square l="100" c="red"></custom-square></pre> + +<p>クラスコンストラクターは非常に単純です。ここでは、要素にシャドウDOMをアタッチし、空の{{htmlelement("div")}} および{{htmlelement("style")}} 要素をシャドウルートにアタッチします:</p> + +<pre class="brush: js">var shadow = this.attachShadow({mode: 'open'}); + +var div = document.createElement('div'); +var style = document.createElement('style'); +shadow.appendChild(style); +shadow.appendChild(div);</pre> + +<p>この例の主要な機能は<code>updateStyle()</code>です。これは要素を取得し、シャドウルートを取得し、その<code><style></code>要素を見つけて、{{cssxref("width")}}, {{cssxref("height")}}, および{{cssxref("background-color")}} をスタイルに追加します。</p> + +<pre class="brush: js">function updateStyle(elem) { + const shadow = elem.shadowRoot; + shadow.querySelector('style').textContent = ` + div { + width: ${elem.getAttribute('l')}px; + height: ${elem.getAttribute('l')}px; + background-color: ${elem.getAttribute('c')}; + } + `; +}</pre> + +<p>実際の更新はすべて、メソッドとしてクラス定義内に配置されるライフサイクルコールバックによって処理されます。 <code>connectedCallback()</code>は、要素がDOMに追加されるたびに実行されます。ここでは、<code>updateStyle()</code>関数を実行して、正方形がその属性で定義されたスタイルになっていることを確認します。</p> + +<pre class="brush: js">connectedCallback() { + console.log('Custom square element added to page.'); + updateStyle(this); +}</pre> + +<p><code>disconnectCallback()</code>および<code>adoptedCallback()</code> コールバックは、要素がDOMから削除されるか、別のページに移動されたときに通知する単純なメッセージをコンソールに記録します。</p> + +<pre class="brush: js">disconnectedCallback() { + console.log('Custom square element removed from page.'); +} + +adoptedCallback() { + console.log('Custom square element moved to new page.'); +}</pre> + +<p><code>attributeChangedCallback()</code>コールバックは、要素の属性の1つが何らかの方法で変更されるたびに実行されます。そのプロパティからわかるように、属性、属性の名前、および古い属性値と新しい属性値を個別に操作することができます。ただし、この場合は、<code>updateStyle()</code>関数を再度実行して、新しい値に従って正方形のスタイルが更新されるようにします。</p> + +<pre class="brush: js">attributeChangedCallback(name, oldValue, newValue) { + console.log('Custom square element attributes changed.'); + updateStyle(this); +}</pre> + +<p>属性が変更されたときに起動する<code>attributeChangedCallback()</code>コールバックを取得するには、属性を監視する必要があることに注意してください。これは、カスタム要素クラス内で<code>static get observedAttributes()</code>メソッドを指定することによって行われます-これは、監視したい属性の名前を含む配列を返します:</p> + +<pre class="brush: js">static get observedAttributes() { return ['c', 'l']; }</pre> + +<p>この例では、これはコンストラクターの最上部に配置されています。</p> + +<div class="note"> +<p><strong>注</strong>: ここで<a href="https://github.com/mdn/web-components-examples/blob/master/life-cycle-callbacks/main.js">完全なJavaScriptソース</a>を検索してください。</p> +</div> + +<h2 id="Polyfills_versus_classes" name="Polyfills_versus_classes">ポリフィル 対 クラス</h2> + +<p>カスタム要素のポリフィルは <code>HTMLElement</code> などのネイティブのコンストラクタに対してパッチを当てることで、単にネイティブのコンストラクタが作成したものとは異なるインスタンスを返すことがあります。<br> + <br> + もし <code>constructor</code> や強制的に <code>super</code> を呼び出す必要があるなら、任意の引数を渡して <code>super</code> を呼び出した結果を返すことを忘れないでください。</p> + +<pre class="brush: js">class CustomElement extends HTMLElement { + constructor(...args) { + const self = super(...args); + // self functionality written in here + // self.addEventListener(...) + // return the right context + return self; + } +}</pre> + +<p>もしコンストラクタ内で何も処理が必要ないならば、単に省略することでネイティブの挙動を維持できます。</p> + +<pre class="brush: js"> constructor(...args) { return super(...args); } +</pre> + +<h2 id="Transpilers_versus_classes" name="Transpilers_versus_classes">トランスパイラ 対 クラス</h2> + +<p>レガシーなブラウザをターゲットとしたBabel 6またはTypeScriptでは、ES2015のクラス構文は期待通りにトランスパイルされない可能性があることに注意してください。Babel 7もしくはBabel 6の <a href="https://www.npmjs.com/package/babel-plugin-transform-builtin-classes">babel-plugin-transform-builtin-classes</a>を使用して、レガシーなブラウザではなくくTypeScriptでES2015をターゲットとすることができます。</p> + +<h2 id="Libraries" name="Libraries">ライブラリ</h2> + +<p>カスタム要素を作る際に抽象度を高めることを目的とした、Web Componentsで実装されたライブラリがあります。その内のいくつかを挙げます。<a href="https://github.com/devpunks/snuggsi" rel="nofollow">snuggsi ツ</a>、<a href="https://x-tag.github.io/" rel="nofollow">X-Tag</a>、<a href="http://slimjs.com/" rel="nofollow">Slim.js</a>、<a href="https://lit-element.polymer-project.org/">LitElement</a>、<a href="https://www.htmlelements.com/">Smart</a>、<a href="https://stenciljs.com">Stencil</a>。</p> diff --git a/files/ja/web/web_components/using_shadow_dom/index.html b/files/ja/web/web_components/using_shadow_dom/index.html new file mode 100644 index 0000000000..3a990d1953 --- /dev/null +++ b/files/ja/web/web_components/using_shadow_dom/index.html @@ -0,0 +1,218 @@ +--- +title: shadow DOM の使い方 +slug: Web/Web_Components/Using_shadow_DOM +translation_of: Web/Web_Components/Using_shadow_DOM +--- +<div> {{DefaultAPISidebar("Web Components")}}</div> + +<p class="summary">Web コンポーネントにおいてカプセル化 (構造やスタイル、挙動を隠し、同じページの他のコードと分離すること) は重要です。これにより他の場所でのクラッシュを防ぎ、またコードが綺麗になります。Shadow DOM API はこの隠され分離された DOM を付加するための方法を提供しています。この記事では Shadow DOM を使う基本を記述しています。</p> + +<div class="note"> +<p><strong>Note</strong>: Shadow DOM は Firefox (version 63以降)、Chrome、Opera、そして Safari でサポートされています。 Chromiumベースの新しいEdge(75以降)もサポートしています。旧Edgeはサポートしていません。</p> +</div> + +<h2 id="High-level_view">High-level view</h2> + +<p>この記事では <a href="/en-US/docs/Web/API/Document_Object_Model/Introduction">DOM (Document Object Model)</a> —ドキュメントにある要素やテキストを表現するノードによって構成された木構造 — に親しんでいる前提で説明します。例として以下の HTML フラグメントを考えます。 </p> + +<pre class="brush: html"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>Simple DOM example</title> + </head> + <body> + <section> + <img src="dinosaur.png" alt="A red Tyrannosaurus Rex: A two legged dinosaur standing upright like a human, with small arms, and a large head with lots of sharp teeth."> + <p>Here we will add a link to the <a href="https://www.mozilla.org/">Mozilla homepage</a></p> + </section> + </body> +</html></pre> + +<p>このフラグメントによって以下のような DOM 構造が構成されます。</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14559/dom-screenshot.png" style="border-style: solid; border-width: 1px; display: block; margin: 0px auto;"></p> + +<p><em>Shadow</em> DOM により、通常の DOM ツリーの要素の下に DOM ツリーを追加し隠すことができます。shadow DOM ツリーは shadow root を根とし、その下には普通の DOM ツリーと同様に任意の要素を追加できます。</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/15788/shadow-dom.png" style="height: 543px; width: 1138px;"></p> + +<p>以下に shadow DOM における用語を定義します。</p> + +<ul> + <li><strong>Shadow host</strong>: shadow DOM が追加された、通常の DOM ノード</li> + <li><strong>Shadow tree</strong>: shadow DOM の中にある DOM ツリー</li> + <li><strong>Shadow boundary</strong>: shadow DOM と通常の DOM の境界</li> + <li><strong>Shadow root</strong>: shadow ツリーの根ノード</li> +</ul> + +<p>shadow DOM 内のノードは、子ノードを追加したり属性付けをしたり、個々のノードのスタイルを element.style.foo と定めたり shadow DOM ツリー全体のスタイルを {{htmlelement("style")}} 要素で定めたりなど、通常の DOM のノードと同様に制御できます。ただし、shadow DOM の内部コードによって外部を制御することは出来ません。 </p> + +<p>shadow DOM は全く新しいものではなく、例えばブラウザにおいて要素の内部構造をカプセル化するために長年使用されていました。 {{htmlelement("video")}} 要素の例を考えます。DOM で見えるものは <code><video></code> 要素のみですが、その shadow DOM の内部ではたくさんのボタンや他の制御コードが含まれています。shadow DOM スペックができたことにより、この機能を実際に操作しカスタム要素で shadow DOM を作ることができるようになりました。 </p> + +<h2 id="基本的な使い方">基本的な使い方</h2> + +<p>shadow root は {{domxref("Element.attachShadow()")}} メソッドを利用して任意の要素に追加することができます。このメソッドではパラメータとして <code>mode</code> オプションを <code>open</code> または <code>closed</code> の値で取ります。 </p> + +<pre class="brush: js">let shadow = elementRef.attachShadow({mode: 'open'}); +let shadow = elementRef.attachShadow({mode: 'closed'});</pre> + +<p><code>open</code> の場合は shadow DOM の内部にメインページに書かれた JavaScript からアクセスできます。以下のように {{domxref("Element.shadowRoot")}} プロパティを利用してアクセスできます。</p> + +<pre class="brush: js">let myShadowDom = myCustomElem.shadowRoot;</pre> + +<p>shadow root を <code>mode: closed</code> で追加した場合、外部から shadow DOM にアクセス出来ず、<code>myCustomElem.shadowRoot</code> は <code>null</code> を返します。<code><video></code> などの shadow DOM を含む既成の要素は <code>closed</code> になっています。</p> + +<div class="note"> +<p><strong>Note</strong>: <a href="https://blog.revillweb.com/open-vs-closed-shadow-dom-9f3d7427d1af">このブログ記事を見るに</a>、実はclosed shadow DOMを回避するのはそんなに難しいことではなく、また、これを完全に隠すことはその価値の割には面倒です。</p> +</div> + +<p>shadow DOM をコンストラクタの一部としてカスタム要素に追加することを考えます。</p> + +<pre class="brush: js">let shadow = this.attachShadow({mode: 'open'});</pre> + +<p>shadow DOM は、通常の DOM の操作に使われる DOM API で操作することができます。</p> + +<pre class="brush: js">var para = document.createElement('p'); +shadow.appendChild(para); +// etc.</pre> + +<h2 id="実用例">実用例</h2> + +<p>カスタム要素内のシンプルなshadow DOM を見てみましょう — <code><a href="https://github.com/mdn/web-components-examples/tree/master/popup-info-box-web-component"><popup-info-box></a></code> (<a href="https://mdn.github.io/web-components-examples/popup-info-box-web-component/">実行例</a>)。このタグはイメージアイコンとテキストを取り、アイコンをページに埋め込みます。アイコンがフォーカスされるとポップアップが表示され、さらなる情報を提供します。<br> + まずは <code>HTMLElement</code> を拡張して <code>PopUpInfo</code> というクラスを定義します。</p> + +<pre class="brush: js">class PopUpInfo extends HTMLElement { + constructor() { + // Always call super first in constructor + super(); + + // write element functionality in here + + ... + } +}</pre> + +<p>クラス定義の際、インスタンスが初期化された時に用意されるあらゆる関数を定義したコンストラクタを定義します。</p> + +<h3 id="shadow_root_の作成">shadow root の作成</h3> + +<p>最初に shadow root をカスタム要素に追加します。</p> + +<pre class="brush: js">// Create a shadow root +var shadow = this.attachShadow({mode: 'open'});</pre> + +<h3 class="brush: js" id="shadow_DOM_構造の作成">shadow DOM 構造の作成</h3> + +<p class="brush: js">次に shadow DOM 構造を作ります。</p> + +<pre class="brush: js">// Create spans +var wrapper = document.createElement('span'); +wrapper.setAttribute('class','wrapper'); +var icon = document.createElement('span'); +icon.setAttribute('class','icon'); +icon.setAttribute('tabindex', 0); +var info = document.createElement('span'); +info.setAttribute('class','info'); + +// Take attribute content and put it inside the info span +var text = this.getAttribute('text'); +info.textContent = text; + +// Insert icon +var imgUrl; +if(this.hasAttribute('img')) { + imgUrl = this.getAttribute('img'); +} else { + imgUrl = 'img/default.png'; +} +var img = document.createElement('img'); +img.src = imgUrl; +icon.appendChild(img); +</pre> + +<h3 class="brush: js" id="shadow_DOM_のスタイル">shadow DOM のスタイル</h3> + +<p class="brush: js">そのあと、 {{htmlelement("style")}} 要素を作り CSS でスタイルを付けます。</p> + +<pre class="brush: js">// Create some CSS to apply to the shadow dom +var style = document.createElement('style'); + +style.textContent = ` +.wrapper { + position: relative; +} + +.info { + font-size: 0.8rem; + width: 200px; + display: inline-block; + border: 1px solid black; + padding: 10px; + background: white; + border-radius: 10px; + opacity: 0; + transition: 0.6s all; + position: absolute; + bottom: 20px; + left: 10px; + z-index: 3; +} + +img { + width: 1.2rem; +} + +.icon:hover + .info, .icon:focus + .info { + opacity: 1; +}`; + +</pre> + +<h3 id="shadow_DOM_を_shadow_root_に追加">shadow DOM を shadow root に追加</h3> + +<p>最後に作成した全ての要素を shadow root に追加します。</p> + +<pre class="brush: js">// attach the created elements to the shadow dom +shadow.appendChild(style); +shadow.appendChild(wrapper); +wrapper.appendChild(icon); +wrapper.appendChild(info);</pre> + +<h3 id="カスタム要素の使用">カスタム要素の使用</h3> + +<p>クラスを定義すると、定義したようにカスタム要素を使用することができます。(<a href="/en-US/docs/Web/Web_Components/Using_custom_elements">Using custom elements</a>)</p> + +<pre class="brush: js">// Define the new element +customElements.define('popup-info', PopUpInfo);</pre> + +<pre class="brush: html"><<span class="pl-ent">popup-info</span> <span class="pl-e">img</span>=<span class="pl-s"><span class="pl-pds">"</span>img/alt.png<span class="pl-pds">"</span></span> <span class="pl-e">text</span>=<span class="pl-s"><span class="pl-pds">"</span>Your card validation code (CVC) is an extra + security feature — it is the last 3 or 4 + numbers on the back of your card.<span class="pl-pds">"</span></span>></pre> + +<div> +<h3 id="内部スタイル_vs_外部スタイル">内部スタイル vs 外部スタイル</h3> + +<p>上述の例では{{htmlelement("style")}}要素を用いてShadow DOMにスタイルを適用しましたが、代わりに{{htmlelement("link")}}要素で外部のスタイルシートを参照することでも完全に実現できます。</p> + +<p>例として、<a href="https://mdn.github.io/web-components-examples/popup-info-box-external-stylesheet/">popup-info-box-external-stylesheet</a> の例を見てください。(<a href="https://github.com/mdn/web-components-examples/blob/master/popup-info-box-external-stylesheet/main.js">ソースコード</a>)</p> + +<pre>// Apply external styles to the shadow dom +const linkElem = document.createElement('link'); +linkElem.setAttribute('rel', 'stylesheet'); +linkElem.setAttribute('href', 'style.css'); + +// Attach the created element to the shadow dom +shadow.appendChild(linkElem);</pre> + +<p> {{htmlelement("link")}}要素がshadow rootの描画をブロックしないため、スタイルシートがロードされている間flash of unstyled content(FOUC)が起こりうることに注意してください。</p> + +<p>多くのモダンブラウザは、共通ノードからコピーされた、または同一のテキストを持つ {{htmlelement("style")}}タグの最適化を実装して、単一のバッキングスタイルシートを共有できるようにしています。この最適化により、外部スタイルと内部スタイルのパフォーマンスは同様になります。</p> + +<h2 id="参考">参考</h2> + +<ul> + <li><a href="/en-US/docs/Web/Web_Components/Using_custom_elements">Using custom elements</a></li> + <li><a href="/en-US/docs/Web/Web_Components/Using_templates_and_slots">Using templates and slots</a></li> +</ul> +</div> diff --git a/files/ja/web/web_components/using_templates_and_slots/index.html b/files/ja/web/web_components/using_templates_and_slots/index.html new file mode 100644 index 0000000000..71f1ac7ca7 --- /dev/null +++ b/files/ja/web/web_components/using_templates_and_slots/index.html @@ -0,0 +1,324 @@ +--- +title: template と slot の使い方 +slug: Web/Web_Components/Using_templates_and_slots +translation_of: Web/Web_Components/Using_templates_and_slots +--- +<div>{{DefaultAPISidebar("Web Components")}}</div> + +<p class="summary">この記事では shadow DOM で使われる {{htmlelement("template")}} と {{htmlelement("slot")}} 要素の使い方を説明します。</p> + +<h2 id="テンプレートの真実">テンプレートの真実</h2> + +<p>あるWebページ上で同じ構造を繰り返し使用する必要がある場合、同じ実装を繰り返し書くよりも、テンプレートのようなものを作って利用する方が合理的でしょう。これは以前から可能でしたが、{{htmlelement("template")}} 要素より簡単に使えるようになりました。 この要素と中身は DOM 上ではレンダリングされませんが、JavaScript から参照することができます。</p> + +<p>以下の簡単なサンプルを見てみましょう。</p> + +<pre class="brush: html"><template id="my-paragraph"> + <p>My paragraph</p> +</template></pre> + +<p>テンプレートの内部はページには表示されません。以下のコードのようにJavaScript を用いて参照を取り DOM に追加するとページ上に表示できます。</p> + +<pre class="brush: js">let template = document.getElementById('my-paragraph'); +let templateContent = template.content; +document.body.appendChild(templateContent);</pre> + +<p>つまらない例ですがすでに有用性は見えてきたでしょう。</p> + +<h2 id="Web_Componentsを利用したテンプレートの使用">Web Componentsを利用したテンプレートの使用</h2> + +<p>テンプレートはそれ自身でも有用ですが web コンポーネントと共に使用することでより上手く使えます。テンプレートを shadow DOM として活用する web コンポーネントを <code><my-paragraph></code> と名付け定義しましょう。</p> + +<pre class="brush: js">customElements.define('my-paragraph', + class extends HTMLElement { + constructor() { + super(); + let template = document.getElementById('my-paragraph'); + let templateContent = template.content; + + const shadowRoot = this.attachShadow({mode: 'open'}) + .appendChild(templateContent.cloneNode(true)); + } +})</pre> + +<p>ここで、テンプレートの内容を使用するために {{domxref("Node.cloneNode()")}} を使用してクローンしたものを shadow root に追加していることに注意してください。</p> + +<p>テンプレートの内容を shadow DOM に追加しているので、テンプレートの内部に {{htmlelement("style")}} 要素を用意しスタイルを含むことができます。このスタイルはカスタム要素の内部でカプセル化されます。これは通常の DOM に追加するだけでは正しく動きません。</p> + +<p>したがって、例えば</p> + +<pre class="brush: html"><template id="my-paragraph"> + <style> + p { + color: white; + background-color: #666; + padding: 5px; + } + </style> + <p>My paragraph</p> +</template></pre> + +<p>こうすれば HTML ドキュメントに以下を追加することで使用できます。</p> + +<pre class="brush: html"><my-paragraph></my-paragraph> +</pre> + +<div class="note"> +<p><strong>注意:</strong> テンプレートはブラウザでよくサポートされています。Shadow DOM APIはデフォルトのFirefox (バージョン63以降) 、Chrome、OperaそしてSafariでサポートされています。Edgeでも現在開発が行われています。</p> +</div> + +<h2 id="スロットによる柔軟性の強化">スロットによる柔軟性の強化</h2> + +<p>ここまでのサンプルでは高々1種類のテキストを表示できるのみで、普通の paragraph よりも使えません。{{htmlelement("slot")}} 要素を用いることで、各要素のインスタンスに異なるテキストを表示させることができます。{{htmlelement("slot")}} は {{htmlelement("template")}} よりサポートが限られており、Chrome 53以降、Opera 40以降、Safari 10以降、Firefox 59以降で実装されていますが、Edge ではまだサポートされていません。slot はその <code>name</code> 属性で区別されており、template の中で任意のマークアップで slot の内容のデフォルト値を埋めることができます。</p> + +<p>上記の例に slot を追加することを考えます。パラグラフの要素を以下のように書くことができます。</p> + +<pre class="brush: html"><p><slot name="my-text">デフォルトテキスト</slot></p></pre> + +<p>slot の内容が定義されていない場合や、ブラウザが slot をサポートしていな場合は <code><my-paragraph></code> は fallback コンテンツを保持し、このサンプルの場合では "デフォルトテキスト" を表示させることになります。</p> + +<p>内容を定義したい slot の名前を {{htmlattrxref("slot")}} 属性に設定した要素を <code><my-paragraph></code> の中に用意すると、その中身が slot の内容になります。中身は HTML 構造を持つ任意のもので埋めることができます。</p> + +<pre class="brush: html"><my-paragraph> + <span slot="my-text">新しいテキストを代入します</span> +</my-paragraph></pre> + +<p>以下のようにも設定できます。</p> + +<pre class="brush: html"><my-paragraph> + <ul slot="my-text"> + <li>新しいテキストを代入します</li> + <li>リストも代入できます</li> + </ul> +</my-paragraph> +</pre> + +<div class="note"> +<p><strong>注意:</strong> スロットに挿入できるのは {{domxref("Slotable")}} な要素に限られます; 要素がスロットに挿入されたとき、<em>slotted</em> と呼ばれます。</p> +</div> + +<p>簡単なサンプルでの説明は以上です。他にも実装してみたい場合は、<a href="https://github.com/mdn/web-components-examples/tree/master/simple-template">GitHub上のサンプルコード</a>をご利用ください(<a href="https://mdn.github.io/web-components-examples/simple-template/">実行例</a>)。</p> + +<h2 id="より踏み込んだ例">より踏み込んだ例</h2> + +<p>他の例もみてみましょう。</p> + +<p>これからのコードは {{htmlelement("slot")}} を {{htmlelement("template")}} と共に使用する方法の例です。以下の2点を目指す JavaScript です。</p> + +<ul> + <li><a href="/en-US/docs/Web/API/ShadowRoot">shadow root</a> の中で <strong><code><element-details></code></strong> 要素を <a href="/en-US/docs/Web/HTML/Element/slot#named-slot">slot</a> を用いて作ること。</li> + <li><strong><code><element-details></code></strong> 要素を、その <a href="/en-US/docs/Web/API/ShadowRoot">shadow root</a> と一緒にレンダリングされるように作ること。つまり、要素の内容が <a href="/en-US/docs/Web/HTML/Element/slot#named-slot">slots</a> の中身に代入されるようになります。</li> +</ul> + +<p>{{htmlelement("slot")}} 要素は {{htmlelement("template")}} 要素なしで使用することが可能です。例えば、 {{HTMLElement("div")}} 要素の中で宣言しても Shadow DOM で使用した場合と同様にプレースホルダーとしての役割は果たします。しかし、{{HTMLElement("template")}} 要素の中で使用する方がより一般的で実用的です。</p> + +<p>テンプレートを利用したコンテナの目的は {{HTMLElement("template")}} を使用することで意味的にわかりやすくすることです。さらに、{{HTMLElement("template")}} の中には {{HTMLElement("td")}} など直接追加して良い要素があり、これらは {{HTMLElement("div")}} 要素の中に追加された場合は消えます。</p> + +<div class="note"> +<p>注意: element-detailsの完全なコードは<a href="https://github.com/mdn/web-components-examples/tree/master/element-details">ここ</a>から見ることができます (<a href="https://mdn.github.io/web-components-examples/element-details/">実行例</a>)。</p> +</div> + +<h3 id="template_をスロットと共に作る">template をスロットと共に作る</h3> + +<p>まず最初に{{htmlelement("template")}} 要素の中に {{htmlelement("slot")}} 要素を作成し、新しい "element-details-template" と名付けた<a href="/en-US/docs/Web/API/DocumentFragment">フラグメント</a>を作ります。</p> + +<pre class="brush: html"><template id="element-details-template"> + <style> + details {font-family: "Open Sans Light",Helvetica,Arial} + .name {font-weight: bold; color: #217ac0; font-size: 120%} + h4 { margin: 10px 0 -8px 0; } + h4 span { background: #217ac0; padding: 2px 6px 2px 6px } + h4 span { border: 1px solid #cee9f9; border-radius: 4px } + h4 span { color: white } + .attributes { margin-left: 22px; font-size: 90% } + .attributes p { margin-left: 16px; font-style: italic } + </style> + <details> + <summary> + <span> + <code class="name">&lt;<slot name="element-name">NEED NAME</slot>&gt;</code> + <i class="desc"><slot name="description">NEED DESCRIPTION</slot></i> + </span> + </summary> + <div class="attributes"> + <h4><span>Attributes</span></h4> + <slot name="attributes"><p>None</p></slot> + </div> + </details> + <hr> +</template> +</pre> + +<p>この {{HTMLElement("template")}} 要素にはいくつかの機能があります。</p> + +<ul> + <li>{{HTMLElement("template")}} には {{HTMLElement("style")}} 要素が実装されており、{{HTMLElement("template")}} が作るフラグメントの中のみに適応されるCSSスタイルを定義できます。 </li> + <li>{{HTMLElement("template")}} は {{htmlelement("slot")}} を使用しており、それぞれの {{htmlattrxref("name", "slot")}} 属性は以下のように定義されています。 + <ul> + <li><code><slot name="element-name"></code></li> + <li><code><slot name="description"></code></li> + <li><code><slot name="attributes"></code></li> + </ul> + </li> + <li>{{HTMLElement("template")}} の中で各 <a href="/en-US/docs/Web/HTML/Element/slot#named-slot">slot</a> は{{HTMLElement("details")}} 要素の中に実装されています。</li> +</ul> + +<h3 id="<template>_から_<element-details>_要素を作る"><template> から <element-details> 要素を作る</h3> + +<p>次に <strong><code><element-details></code></strong> と名付けた新しいカスタム要素を作りましょう。 上で確認した簡単な例と同様に、{{DOMXref("Element.attachShadow")}} を利用してカスタム要素に <a href="/en-US/docs/Web/API/ShadowRoot">shadow root</a> を追加します。</p> + +<pre class="brush: js">customElements.define('element-details', + class extends HTMLElement { + constructor() { + super(); + var template = document + .getElementById('element-details-template') + .content; + const shadowRoot = this.attachShadow({mode: 'open'}) + .appendChild(template.cloneNode(true)); + } +}) +</pre> + +<h3 id="名前付きスロットと共に_<element-details>_要素を使う">名前付きスロットと共に <element-details> 要素を使う</h3> + +<p>では <strong><code><element-details></code></strong> 要素を実際に使ってみましょう。 </p> + +<pre class="brush: html"><element-details> + <span slot="element-name">slot</span> + <span slot="description">A placeholder inside a web + component that users can fill with their own markup, + with the effect of composing different DOM trees + together.</span> + <dl slot="attributes"> + <dt>name</dt> + <dd>The name of the slot.</dd> + </dl> +</element-details> + +<element-details> + <span slot="element-name">template</span> + <span slot="description">A mechanism for holding client- + side content that is not to be rendered when a page is + loaded but may subsequently be instantiated during + runtime using JavaScript.</span> +</element-details> +</pre> + +<p>このコードについて以下の点に注意してください。</p> + +<ul> + <li>2つの <strong><code><element-details></code></strong> 要素が使用されており、いずれも {{htmlattrxref("slot")}} 属性を <code>"element-name"</code> および <code>"description"</code> と指定することで対応する <a href="/en-US/docs/Web/HTML/Element/slot#named-slot">slot</a> を参照しています。</li> + <li>1つ目の <strong><code><element-details></code></strong> 要素でのみ <code>"attributes"</code> と名付けられた <a href="/en-US/docs/Web/HTML/Element/slot#named-slot">slot</a> を参照しています。2個目の <code><strong><element-details</strong>></code> 要素では参照していません。</li> + <li>1つ目の <code><<strong>element-details></strong></code> 要素は {{HTMLElement("dl")}} 要素を用いて <code>"attributes"</code> と名付けられた <a href="/en-US/docs/Web/HTML/Element/slot#named-slot">slot</a> を参照しています。</li> +</ul> + +<h3 id="スタイルを追加する">スタイルを追加する</h3> + +<p>最後にもう少しCSSスタイルを追加します。これは、1個目の <code><element-details></code> の中で使われている {{HTMLElement("dl")}}、{{HTMLElement("dt")}}、{{HTMLElement("dd")}} 要素のために用意されています。 </p> + +<pre class="brush: css"> dl { margin-left: 6px; } + dt { font-weight: bold; color: #217ac0; font-size: 110% } + dt { font-family: Consolas, "Liberation Mono", Courier } + dd { margin-left: 16px } +</pre> + +<div class="hidden"> +<pre class="brush: css">body { margin-top: 47px }</pre> +</div> + +<h3 id="結果">結果</h3> + +<p>以上のコードを繋げてどのような結果がレンダリングされるかを確認しましょう。</p> + +<p>{{ EmbedLiveSample('full_example', '300','400','https://mdn.mozillademos.org/files/14553/element-details.png','') }}</p> + +<p>以下のことに着目してください。</p> + +<ul> + <li>ドキュメント内で <strong><code><element-details></code></strong> 要素のインスタンスは {{HTMLElement("details")}} 要素を直接使用しませんが、 <a href="/en-US/docs/Web/API/ShadowRoot">shadow root</a> が {{HTMLElement("details")}} を生成することでレンダリングされます。</li> + <li>レンダリングされた {{HTMLElement("details")}} の出力結果で、<strong><code><element-details></code></strong> 要素のコンテンツは <a href="/en-US/docs/Web/API/ShadowRoot">shadow root</a> から<a href="/en-US/docs/Web/HTML/Element/slot#named-slot">名前付きスロット</a>を埋め込みます。言い換えれば、<strong><code><element-details></code></strong> 要素のDOMツリーは <a href="/en-US/docs/Web/API/ShadowRoot">shadow root</a> のコンテンツと共に構成されます。</li> + <li>両方の <strong><code><element-details></code></strong> 要素おいて、<code>"attributes"</code> 名前付きスロットが配置される前に、 <a href="/en-US/docs/Web/API/ShadowRoot">shadow root</a> から自動的に <strong>Attributes </strong>見出しは自動的に追加されます。</li> + <li>最初の <strong><code><element-details></code></strong> は <a href="/en-US/docs/Web/API/ShadowRoot">shadow root</a> から<a href="/en-US/docs/Web/HTML/Element/slot#named-slot">名前付きスロット</a>を明示的に参照している {{HTMLElement("dl")}} 要素を持つため、{{HTMLElement("dl")}} のコンテンツは <a href="/en-US/docs/Web/API/ShadowRoot">shadow root</a> から <code>"attributes"</code> <a href="/en-US/docs/Web/HTML/Element/slot#named-slot">名前付きスロット</a>を置き換えています。</li> + <li>二つ目の <strong><code><element-details></code></strong> は <a href="/en-US/docs/Web/API/ShadowRoot">shadow root</a> から<a href="/en-US/docs/Web/HTML/Element/slot#named-slot">名前付きスロット</a>を明示的に参照していないため、<a href="/en-US/docs/Web/HTML/Element/slot#named-slot">名前付きスロット</a>のコンテンツは <a href="/en-US/docs/Web/API/ShadowRoot">shadow root</a> のデフォルトのコンテンツが埋め込まれます。</li> +</ul> + +<div class="hidden"> +<h5 id="full_example">full example</h5> + +<pre class="brush: html"><!DOCTYPE html> +<html> + <head> + <title>slot example</title> + <style> + + dl { margin-left: 6px; } + dt { font-weight: bold; color: #217ac0; font-size: 110% } + dt { font-family: Consolas, "Liberation Mono", Courier } + dd { margin-left: 16px } + + </style> + </head> + <body> + <template id="element-details-template"> + <style> + details {font-family: "Open Sans Light",Helvetica,Arial} + .name {font-weight: bold; color: #217ac0; font-size: 120%} + h4 { margin: 10px 0 -8px 0; } + h4 span { background: #217ac0; padding: 2px 6px 2px 6px } + h4 span { border: 1px solid #cee9f9; border-radius: 4px } + h4 span { color: white } + .attributes { margin-left: 22px; font-size: 90% } + .attributes p { margin-left: 16px; font-style: italic } + </style> + <details> + <summary> + <span> + <code class="name">&lt;<slot name="element-name">NEED NAME</slot>&gt;</code> + <i class="desc"><slot name="description">NEED DESCRIPTION</slot></i> + </span> + </summary> + <div class="attributes"> + <h4><span>Attributes</span></h4> + <slot name="attributes"><p>None</p></slot> + </div> + </details> + <hr> + </template> + + <element-details> + <span slot="element-name">slot</span> + <span slot="description">A placeholder inside a web + component that users can fill with their own markup, + with the effect of composing different DOM trees + together.</span> + <dl slot="attributes"> + <dt>name</dt> + <dd>The name of the slot.</dd> + </dl> + </element-details> + + <element-details> + <span slot="element-name">template</span> + <span slot="description">A mechanism for holding client- + side content that is not to be rendered when a page is + loaded but may subsequently be instantiated during + runtime using JavaScript.</span> + </element-details> + + <script> + customElements.define('element-details', + class extends HTMLElement { + constructor() { + super(); + const template = document + .getElementById('element-details-template') + .content; + const shadowRoot = this.attachShadow({mode: 'open'}) + .appendChild(template.cloneNode(true)); + } + }) + </script> + </body> +</html></pre> +</div> |