Shadow DOM 101

はじめに

ウェブ コンポーネントとは、次のような最先端の標準をまとめたものです。

  1. ウィジェットを作成できるようにする
  2. 確実に再利用できる
  3. ...新しいバージョンのコンポーネントの 内部実装の詳細を変更します。

この場合、HTML/JavaScript をどのような場合に使用すべきか、 どのような場合に使うべきでしょうかいいえ。HTML と JavaScript によって、 インタラクティブなビジュアル要素ですウィジェットは、インタラクティブで視覚的な要素です。これは、 HTML と JavaScript のスキルを活用すると、 ウィジェットの開発ですWeb Components 標準は できます。

しかしウィジェットを HTML と JavaScript が使いづらい: ウィジェット内の DOM ツリーは ページの残りの部分からカプセル化されます。カプセル化の欠如により ドキュメント スタイルシートがパーツに誤って適用される可能性がある ウィジェット内JavaScript によってコード内の要素が誤って ウィジェット内ID がウィジェット内の ID と重複することがあります。 といった具合です

Web Components は、次の 3 つの部分で構成されています。

  1. テンプレート
  2. Shadow DOM
  3. カスタム要素

Shadow DOM は、DOM ツリーのカプセル化の問題に対処しています。「 Web Components の 4 つの部分は連携して動作するように設計されていますが、 使用する Web Components の部分も選択できます。この このチュートリアルでは Shadow DOM の使用方法について説明します。

をご覧ください。

ハロー、シャドー ワールド

Shadow DOM では、要素に関連付けた新しい種類のノードを できます。この新しい種類のノードはシャドウルートと呼ばれます。シャドウルートが関連付けられている要素は、シャドウと呼ばれます。 提供しますシャドウホストのコンテンツがレンダリングされていません。内容 代わりにシャドウルートがレンダリングされます。

たとえば、次のようなマークアップがあるとします。

<button>Hello, world!</button>
<script>
var host = document.querySelector('button');
var root = host.createShadowRoot();
root.textContent = 'こんにちは、影の世界!';
</script>

<button id="ex1a">Hello, world!</button>
<script>
function remove(selector) {
  Array.prototype.forEach.call(
      document.querySelectorAll(selector),
      function (node) { node.parentNode.removeChild(node); });
}

if (!HTMLElement.prototype.createShadowRoot) {
  remove('#ex1a');
  document.write('<img src="SS1.png" alt="Screenshot of a button with \'Hello, world!\' on it.">');
}
</script>

ページがどのように表示されるか

<button id="ex1b">Hello, world!</button>
<script>
(function () {
  if (!HTMLElement.prototype.createShadowRoot) {
    remove('#ex1b');
    document.write('<img src="SS2.png" alt="Screenshot of a button with \'Hello, shadow world!\' in Japanese on it.">');
    return;
  }
  var host = document.querySelector('#ex1b');
  var root = host.createShadowRoot();
  root.textContent = 'こんにちは、影の世界!';
})();
</script>

それだけでなく、ページ上の JavaScript からボタンの textContent のお客様は 「こんにちは、影の世界!」でも「Hello, world!」これは DOM サブツリーが カプセル化されています。

プレゼンテーションからコンテンツを分離する

次に、Shadow DOM を使用して、コンテンツを複数の 説明します。次のような名タグがあるとします。

<style>
.ex2a.outer {
  border: 2px solid brown;
  border-radius: 1em;
  background: red;
  font-size: 20pt;
  width: 12em;
  height: 7em;
  text-align: center;
}
.ex2a .boilerplate {
  color: white;
  font-family: sans-serif;
  padding: 0.5em;
}
.ex2a .name {
  color: black;
  background: white;
  font-family: "Marker Felt", cursive;
  font-size: 45pt;
  padding-top: 0.2em;
}
</style>
<div class="ex2a outer">
  <div class="boilerplate">
    Hi! My name is
  </div>
  <div class="name">
    Bob
  </div>
</div>

マークアップは次のとおりです。今日書く内容です。いいえ Shadow DOM を使用します。

<style>
.outer {
  border: 2px solid brown;
  border-radius: 1em;
  background: red;
  font-size: 20pt;
  width: 12em;
  height: 7em;
  text-align: center;
}
.boilerplate {
  color: white;
  font-family: sans-serif;
  padding: 0.5em;
}
.name {
  color: black;
  background: white;
  font-family: "Marker Felt", cursive;
  font-size: 45pt;
  padding-top: 0.2em;
}
</style>
<div class="outer">
  <div class="boilerplate">
    Hi! My name is
  </div>
  <div class="name">
    Bob
  </div>
</div>

DOM ツリーにはカプセル化がないため、 ドキュメントに公開されます。ページの他の要素が 誤って同じクラス名をスタイル設定やスクリプト作成に使用してしまうことがある場合は、 大変なことになるよ。

ちょっと残念に思うかもしれません。

ステップ 1: プレゼンテーションの詳細を非表示にする

意味的には、次のことが重要になるでしょう。

  • 名前のタグです。
  • 名前は「ボブ」です。

まず、求める真の意味により近いマークアップを作成します。

<div id="nameTag">Bob</div>

次に、表示に使用するすべてのスタイルと div を <template> 要素:

<div id="nameTag">Bob</div>
<template id="nameTagTemplate">
<span class="unchanged"><style>
.outer {
  border: 2px solid brown;

  … same as above …

</style>
<div class="outer">
  <div class="boilerplate">
    Hi! My name is
  </div>
  <div class="name">
    Bob
  </div>
</div></span>
</template>

この時点でレンダリングされるのは「Bob」だけです。なぜなら、 プレゼンテーション用 DOM 要素を <template> 要素の場合、レンダリングされませんが、 JavaScript からアクセスできます。これを シャドウルートを設定します。

<script>
var shadow = document.querySelector('#nameTag').createShadowRoot();
var template = document.querySelector('#nameTagTemplate');
var clone = document.importNode(template.content, true);
shadow.appendChild(clone);

これで Shadow ルートが設定され、name タグは ] をクリックします。名前タグを右クリックして では、意味のあるマークアップであることが確認できます。

<div id="nameTag">Bob</div>

これは、Shadow DOM を使用して、 ドキュメントのネームサーバーのプレゼンテーションの詳細。「 プレゼンテーションの詳細は Shadow DOM にカプセル化されます。

ステップ 2: コンテンツをプレゼンテーションから分離する

名前タグによってページのプレゼンテーションの詳細が非表示になりましたが、 プレゼンテーションとコンテンツを分離することはありません。これは、 コンテンツ(「Bob」という名前)がページ内にあり、 シャドウルートにコピーしたディレクトリです変更を 2 か所で行う必要があり、 発生しがちです

HTML 要素は構成です。表内にボタンを配置したり、 できます。ここで必要なのは構成です。名前タグは 「Hi!」の赤色の背景の構図にテキスト、 わかります。

コンポーネントの作成者であるユーザーが、コンポーネントの <content> という新しい要素を使用しています。この ウィジェットの表示中に挿入ポイントが作成され、 挿入ポイントで、シャドウホストからコンテンツをチェリーピックして表示 できます。

Shadow DOM のマークアップを次のように変更すると、次のようになります。

<span class="unchanged"><template id="nameTagTemplate">
<style>
  …
</style></span>
<div class="outer">
  <div class="boilerplate">
    Hi! My name is
  </div>
  <div class="name">
    <content></content>
  </div>
</div>
<span class="unchanged"></template></span>

名前タグがレンダリングされると、シャドウホストのコンテンツは <content> 要素が配置されている場所に投影 表示されます。

ドキュメントの構造がシンプルになりました。名前が 1 か所にまとめられますページで 次のように記述します。

document.querySelector('#nameTag').textContent = 'Shellie';

これで完了です。名前タグのレンダリングが自動的に更新されます。 これは、ウェブページの内容を射影し、 <content> を使って名前タグを配置します。

<div id="ex2b">

これで、コンテンツとプレゼンテーションを分離できました。 コンテンツがドキュメントに含まれている。表示は Shadow DOM 内にあります。 指定した日時にブラウザで自動的に同期されます レンダリングされます。

ステップ 3: 利益

コンテンツとプレゼンテーションを分離することで、 コンテンツを操作するコードです。この例では、name タグの例で 必要なのは、Terraform を含む単純な構造に <div> を複数ではなく 1 つにすることをおすすめします。

プレゼンテーションを変更する場合、 あります。

たとえば、名タグをローカライズするとします。名前である ドキュメント内のセマンティック コンテンツは変わりません。

<div id="nameTag">Bob</div>

シャドウルートの設定コードは同じままです。クラウド コンピューティング モデルに シャドウルートの変更:

<template id="nameTagTemplate">
<style>
.outer {
  border: 2px solid pink;
  border-radius: 1em;
  background: url(sakura.jpg);
  font-size: 20pt;
  width: 12em;
  height: 7em;
  text-align: center;
  font-family: sans-serif;
  font-weight: bold;
}
.name {
  font-size: 45pt;
  font-weight: normal;
  margin-top: 0.8em;
  padding-top: 0.2em;
}
</style>
<div class="outer">
  <div class="name">
    <content></content>
  </div>
  と申します。
</div>
</template>

現在のウェブの状況に比べると、大幅に進歩しています。 名前更新コードは、構成の コンポーネントです。氏名 インフラストラクチャの更新コードでは、構成を 説明しますレンダリングの対象について検討すると、名前は 英語の 2 番目(「Hi!「私の名前」)ですが、日本語では最初の名前です。 (「」)を参照してください。この区別は、意味的には無意味です。 表示される名前を更新するという観点から その詳細を名前更新コードで認識する必要はありません

追加の実習: 高度な投影

上記の例では、<content> 要素には、 シャドーホストからすべてのコンテンツをチェリーピックします。 select 属性に、その属性の コンテンツ要素のプロジェクト複数のコンテンツを使用して あります。

たとえば、次の内容を含むドキュメントがあるとします。

<div id="nameTag">
  <div class="first">Bob</div>
  <div>B. Love</div>
  <div class="email">bob@</div>
</div>

もう一つは、CSS セレクタを使用して特定のコンテンツを選択する Shadow ルートです。

<div style="background: purple; padding: 1em;">
  <div style="color: red;">
    <content **select=".first"**></content>
  </div>
  <div style="color: yellow;">
    <content **select="div"**></content>
  </div>
  <div style="color: blue;">
    <content **select=".email">**</content>
  </div>
</div>

<div class="email"> 要素は両方の要素で照合される <content select="div"> 要素と <content select=".email"> 要素。ボブのメールが どのような色で表示されますか?

その答えは、Bob のメールアドレスが 1 回しか表示されておらず、黄色であるためです。

なぜなら、Shadow DOM をハッキングした人が知っているように、 実際に画面にレンダリングされるツリーを構築する作業は 盛り上がりましょうコンテンツ要素は、 バックステージの Shadow DOM レンダリングに読み込みます。 ありませんこれらの招待状は順番に配信されます。攻撃者に 招待は、その宛先(つまり、 select 属性。)コンテンツは 1 回 招待に応じて常に招待を承諾し( できます。それ以降の招待状がそのアドレスに再び送信された場合、 誰も家にいないし、パーティーにも来ない。

上記の例では、<div class="email"> は次と一致します。 div セレクタと .email の両方 コンテンツ要素が div を含むため、 ドキュメントの先頭にあるセレクタに <div class="email"> は黄色のパーティーに参加し、 誰もブルーパーティーに行けません(これにより、 なぜこんなに青いのか、悲しみは会社を愛しているから、あなたは ありません。)

どのグループにも招待されても まったく表示されなくなります。これが、「Hello, world」というテキストに起こったことです。 見てみましょう。これは、高いスループットを達成したい場合に便利です。 根本的に異なる場合があります。つまり、セマンティック モデルを これはページ内のスクリプトがアクセスできるドキュメントで、 これをレンダリング用に拡張し、まったく別の 構築する方法を説明します。

たとえば、HTML には日付選択ツールがあります。「<input type="date">」と入力すると、見やすいポップアップ カレンダーが表示されます。では、 デザートの日付の範囲をユーザーが選択できるようにする 島での休暇(赤いつる植物でできたハンモックがある)マイページ 次のようにドキュメントを設定します。

<div class="dateRangePicker">
  <label for="start">Start:</label>
  <input type="date" name="startDate" id="start">
  <br>
  <label for="end">End:</label>
  <input type="date" name="endDate" id="end">
</div>

表を使って洗練されたカレンダーを作成する Shadow DOM を作成します。 期間がハイライト表示されますユーザーが カレンダー内の日付が更新されると、コンポーネントは startDate と endDate の入力。ユーザーがフォームを送信すると、 値が送信されます。

ドキュメントにラベルを含めないのはなぜですか? 表示されますか?これは、ユーザーがブラウザでフォームを表示した場合です。 未対応の場合でも、フォームは使用可能ですが、 きれいです。次のような画面が表示されます。

<div class="dateRangePicker">
  <label for="start">Start:</label>
  <input type="date" name="startDate" id="start">
  <br>
  <label for="end">End:</label>
  <input type="date" name="endDate" id="end">
</div>

Shadow DOM 101 に合格

これで Shadow DOM の基本は終わりです。Shadow DOM 101 の知識が身につきます。Google Chat では たとえば Shadow DOM では、複数の Shadow を 1 つのシャドーホストか、カプセル化用のネストされたシャドウ、または モデル駆動ビュー(MDV)と Shadow DOM を使用して、ページをウェブ コンポーネントは Shadow DOM ではありません。

これについては今後の投稿で説明します。