Shadow DOM について
・ | Shadow DOM について |
・ | ShadowRoot を作成する |
・ | ShadowRoot 内のコンテンツについて |
・ | ShadowRoot の機能について |
・ | Element の追加機能について |
・ | <SLOT> 要素について |
Shadow DOM について
■Shadow DOM について
Shadow DOM は、Web Components 関連の機能です。(実験段階)
http://www.w3.org/TR/shadow-dom/ (Working Draft)
複雑な入れ子構造になっている DOM ツリーを、あたかも一体化した1つの要素であるかのように、取り扱えるようになります。
■ <VIDEO> 要素の実例
例えば、<VIDEO> 要素のコントロール部分は、Shadow DOM で実装されています。
内部には、DOM ツリーが存在しますが、隠匿されています。
<VIDEO> 要素は、あたかも一体化した1つの要素のように取り扱うことができます。
■ Shadow Host について
もし作成した場合、その任意の要素は、Shadow Host となります。
Shadow Host に子孫が存在する場合、それらは非表示な状態へと変化します。
■ ShadowRoot について
ShadowRoot は、DOM オブジェクトの一種です。
DocumentFragment インターフェースを継承しています。
主な機能については、こちらで解説しています。
■ Shadow ツリーについて
■ Shadow ツリーを構築する
ShadowRoot の、ノードリストに、任意の DOM オブジェクトを登録します。
ShadowRoot を最上位とした、Shadow ツリーを構築する事ができます。
Shadow ツリーは、基本的に JavaScript から動的に構築します。
<TEMPLATE> 要素を使って、静的に準備しておく事もできます。
■ Shadow Host の描画について
Shadow Host の子孫は、ブラウザに表示されなくなります。
かわりに、ShadowRoot 内の Shadow ツリーが表示されるようになります。
■ Shadow ツリーのカプセル化について
Shadow ツリーは、隠匿された状態となります。
旧世代の API では、ShadowRoot 内にアクセスする事はできません。
ShadowRoot を作成する
■ ShadowRoot オブジェクトを作成する
attachShadow() メソッドを使用します。
Element.attachShadow( ShadowRootInit ) :ShadowRoot
引数(第01引数) | Object | ShadowRootInit オブジェクトを指定。 |
戻り値 | ShadowRoot | ShadowRoot オブジェクトが得られる。 |
■ ShadowRootInit オブジェクトについて
新規にオブジェクトを作成し、以下のプロパティを追加します。
プロパティ名 | 型 | 説明 |
mode | String | 公開モードを設定する。 |
■作成例
ShadowRoot オブジェクトを作成し、Shadow ツリーを構築する
<html>
<body>
<div id="aaa" >
<span style="color:#F00;">あいうえお</span>
</div>
<script type="text/javascript">
<!--
// ------------------------------------------------------------
// "aaa" という ID 属性のエレメントを取得する
// ------------------------------------------------------------
var element = document.getElementById("aaa");
// ------------------------------------------------------------
// ShadowRootInit オブジェクトを作成する
// ------------------------------------------------------------
var shadow_root_init = new Object();
// 公開モードを設定する
shadow_root_init.mode = "closed";
// ------------------------------------------------------------
// ShadowRoot オブジェクトを作成する
// ------------------------------------------------------------
var shadow_root = element.attachShadow( shadow_root_init );
// ------------------------------------------------------------
// HTML 文字列をセットして、Shadow ツリーを構築する
// ------------------------------------------------------------
shadow_root.innerHTML = '<span style="color:#00F;">かきくけこ</span>';
//-->
</script>
</body>
</html>
■公開モードについて(ShadowRootMode)
以下の公開モードが定義されています。
文字列 | 型 | 説明 |
"open" | String | Shadow ツリーを第三者に公開する。 |
"closed" | String | Shadow ツリーを第三者に公開しない。(非公開モード) |
■非公開モードについて
ShadowRoot オブジェクトを取得できるのは、attachShadow() メソッドを使用した当事者のみです。
非公開モードの場合
// ------------------------------------------------------------
// 要素を作成する
// ------------------------------------------------------------
var element = document.createElement("div");
// ------------------------------------------------------------
// ShadowRoot オブジェクトを非公開モードで作成する(作成した当事者のみが、戻り値から ShadowRoot オブジェクトを取得できる)
// ------------------------------------------------------------
var shadow_root0 = element.attachShadow( { mode:"closed" } );
// ------------------------------------------------------------
// ShadowRoot オブジェクトを取得する(第三者は、ShadowRoot オブジェクトを取得できない)
// ------------------------------------------------------------
var shadow_root1 = element.shadowRoot;
// ------------------------------------------------------------
// 出力テスト
// ------------------------------------------------------------
console.log(shadow_root0);
console.log(shadow_root1); // null
■ 作成済みの ShadowRoot オブジェクトを取得する
shadowRoot プロパティを使用します。
取得に失敗する場合は、null が得られます。(非公開モードなど)
作成済みの ShadowRoot オブジェクトを取得する
// ------------------------------------------------------------
// 要素を作成する
// ------------------------------------------------------------
var element = document.createElement("div");
// ------------------------------------------------------------
// ShadowRoot オブジェクトを作成する
// ------------------------------------------------------------
var shadow_root0 = element.attachShadow( { mode:"open" } );
// ------------------------------------------------------------
// ShadowRoot オブジェクトを取得する
// ------------------------------------------------------------
var shadow_root1 = element.shadowRoot;
// ------------------------------------------------------------
// 出力テスト
// ------------------------------------------------------------
console.log(shadow_root1);
console.log(shadow_root0 === shadow_root1); // true
ShadowRoot 内のコンテンツについて
■ ShadowRoot 内に Shadow ツリーを構築する
■ innerHTML プロパティを使用する
ShadowRoot は、innerHTML プロパティに対応しています。
「HTML 文字列」を指定して、Shadow ツリーを構築する事ができます。
HTML 文字列をセットして、Shadow ツリーを構築する
// ------------------------------------------------------------
// DIV 要素を作成する
// ------------------------------------------------------------
var element = document.createElement("div");
// ------------------------------------------------------------
// ShadowRoot オブジェクトを作成する
// ------------------------------------------------------------
var shadow_root = element.attachShadow( { mode:"open" } );
// ------------------------------------------------------------
// HTML 文字列をセットして、Shadow ツリーを構築する
// ------------------------------------------------------------
shadow_root.innerHTML = '<span style="color:#c00; background:#fee;" >あいうえお</span>';
// ------------------------------------------------------------
// BODY 要素のノードリストに登録する
// ------------------------------------------------------------
document.body.appendChild(element);
■ DOM API を使用する
ShadowRoot は、Node インターフェースを継承しています。
ShadowRoot のノードリストに、任意の DOM オブジェクトを登録します。
DOM API を使って、Shadow ツリーを構築する
// ------------------------------------------------------------
// DIV 要素を作成する
// ------------------------------------------------------------
var shadow_host = document.createElement("div");
// ------------------------------------------------------------
// ShadowRoot オブジェクトを作成する
// ------------------------------------------------------------
var shadow_root = shadow_host.attachShadow( { mode:"open" } );
// ------------------------------------------------------------
// SPAN 要素を作成する
// ------------------------------------------------------------
var element = document.createElement("SPAN");
// ------------------------------------------------------------
// テキストノードを作成する
// ------------------------------------------------------------
var text_node = document.createTextNode("あいうえお");
// ------------------------------------------------------------
// ShadowRoot のノードリストに登録する
// ------------------------------------------------------------
shadow_root.appendChild(element);
element.appendChild(text_node);
// ------------------------------------------------------------
// BODY 要素のノードリストに登録する
// ------------------------------------------------------------
document.body.appendChild(shadow_host);
■ <TEMPLATE> 要素を使用する
<TEMPLATE> タグ内に記述した子孫は、専用のサブツリーに登録されています。
これらの DOM オブジェクトは、不活性な状態となります。
例えば、<SCRIPT> 要素などは実行されません。
例えば、外部リソースへのアクセスは発生しません。
不活性な要素を動作させるには、通常のノードリストに再配置します。
<TEMPLATE> 要素内のコンテンツにアクセスするには、content プロパティを使用します。
DocumentFragment オブジェクトが得られます。
<TEMPLATE> 要素を使って、Shadow ツリーを構築する
<html>
<body>
<template id="my_template" >
<span style="color:#c00; background:#fee;" >あいうえお</span> <br>
<span style="color:#0c0; background:#efe;" >かきくけこ</span> <br>
<span style="color:#c0c; background:#eef;" >さしすせそ</span> <br>
</template>
<div id="my_host" ></div>
<script type="text/javascript">
<!--
// ------------------------------------------------------------
// "my_template" という ID 属性のエレメントを取得する
// ------------------------------------------------------------
var template = document.getElementById("my_template");
// ------------------------------------------------------------
// "my_host" という ID 属性のエレメントを取得する
// ------------------------------------------------------------
var shadow_host = document.getElementById("my_host");
// ------------------------------------------------------------
// ShadowRoot オブジェクトを作成する
// ------------------------------------------------------------
var shadow_root = shadow_host.attachShadow( { mode:"open" } );
// ------------------------------------------------------------
// テンプレート内のコンテンツを複製する
// ------------------------------------------------------------
var content = template.content.cloneNode(true);
// ------------------------------------------------------------
// 複製したコンテンツを ShadowRoot 内に配置する
// ------------------------------------------------------------
shadow_root.appendChild(content);
//-->
</script>
</body>
</html>
■ Shadow ツリーにアクセスする
■ DOM API を使用する
また、ShadowRoot は、以下のメソッドに対応しています。(一部抜粋)
メソッド名 | 説明 |
getElementById() | ID 属性からエレメントを取得する |
■ ShadowRoot 内のイベントについて
■ ShadowRoot 内の伝達について
ShadowRoot 内で発生したイベントの詳細な情報は、ShadowRoot まで伝達されます。
■ Shadow Host から祖先への伝達について
ShadowRoot の外側への伝達は、カプセル化されます。
Shadow Host 自体にイベントが発生したかのように通知されます。
■ ShadowRoot のイベントについて
ShadowRoot は、イベントリスナーのみ対応しています。
Element ではないので、イベントプロパティはありません。
■イベントの伝達順序を確認する
ShadowRoot 内のイベントの伝達順序を確認する
<html>
<body>
<template id="my_template" >
<form id="my_form">
<input type="button" value="a" >
<input type="button" value="b" >
<input type="button" value="c" >
</form>
</template>
<div id="my_host" ></div>
<script type="text/javascript">
<!--
// ------------------------------------------------------------
// DOM オブジェクトのすべての子孫を検索する関数
// ------------------------------------------------------------
function DomNodeFindAllDescendants(node,func){
function f(n){
var nodes = n.childNodes;
var i;
var num = nodes.length;
var a = new Array();
for(i=0;i < num;i++){ a[i] = nodes[i]; }
for(i=0;i < num;i++){
node = func(a[i]);
if(node){ return node; }
node = f(a[i]);
if(node){ return node; }
}
return null;
}
return f(node);
}
// ------------------------------------------------------------
// "my_template" という ID 属性のエレメントを取得する
// ------------------------------------------------------------
var template = document.getElementById("my_template");
// ------------------------------------------------------------
// "my_host" という ID 属性のエレメントを取得する
// ------------------------------------------------------------
var shadow_host = document.getElementById("my_host");
// ------------------------------------------------------------
// ShadowRoot オブジェクトを作成する
// ------------------------------------------------------------
var shadow_root = shadow_host.attachShadow( { mode:"open" } );
// ------------------------------------------------------------
// テンプレート内のコンテンツを複製し、ShadowRoot 内に配置する
// ------------------------------------------------------------
var content = template.content.cloneNode(true);
shadow_root.appendChild(content);
// ------------------------------------------------------------
// クリックされたときに実行される関数
// ------------------------------------------------------------
function MouseClickFunc (e){
console.log(" ----- ");
console.log("phase :" , e.eventPhase);
console.log("current:" , e.currentTarget);
console.log("target :" , e.target);
}
// ------------------------------------------------------------
// リッスンを開始する(Shadow Host から祖先)
// ------------------------------------------------------------
window.addEventListener("click" , MouseClickFunc , true);
window.addEventListener("click" , MouseClickFunc , false);
document.addEventListener("click" , MouseClickFunc , true);
document.addEventListener("click" , MouseClickFunc , false);
DomNodeFindAllDescendants(document,function(node){
node.addEventListener("click" , MouseClickFunc , true);
node.addEventListener("click" , MouseClickFunc , false);
return null;
});
// ------------------------------------------------------------
// リッスンを開始する(ShadowRoot 内)
// ------------------------------------------------------------
shadow_root.addEventListener("click" , MouseClickFunc , true);
shadow_root.addEventListener("click" , MouseClickFunc , false);
DomNodeFindAllDescendants(shadow_root,function(node){
node.addEventListener("click" , MouseClickFunc , true);
node.addEventListener("click" , MouseClickFunc , false);
return null;
});
//-->
</script>
</body>
</html>
■ ShadowRoot 内のスタイルシートについて
■ ShadowRoot 内のスタイルシートについて
セレクタの検索範囲は、ShadowRoot 内に限定されます。
ShadowRoot 内のスタイルシートの適用範囲は、Shadow ツリーのみです。
■ ShadowRoot 内のスタイルシートをすべて取得する
styleSheets プロパティを使用します。
styleSheets プロパティから、CSSStyleSheetList オブジェクトが得られます。
スタイルシートについては、こちらで解説しています。
■ ShadowRoot 内のスタイルシートを確認する
ShadowRoot 内のスタイルシートを確認する
<html>
<body>
<template id="my_template" >
<style type="text/css"> </style>
<style type="text/css"> </style>
<style type="text/css">
#aaa{
color:#c00; background:#fee;
}
#bbb{
color:#0c0; background:#efe;
}
#ccc{
color:#c0c; background:#eef;
}
</style>
<div id="aaa" >あいうえお</div> <br>
<div id="bbb" >かきくけこ</div> <br>
<div id="ccc" >さしすせそ</div> <br>
</template>
<div id="my_host" ></div>
<script type="text/javascript">
<!--
// ------------------------------------------------------------
// "my_template" という ID 属性のエレメントを取得する
// ------------------------------------------------------------
var template = document.getElementById("my_template");
// ------------------------------------------------------------
// "my_host" という ID 属性のエレメントを取得する
// ------------------------------------------------------------
var shadow_host = document.getElementById("my_host");
// ------------------------------------------------------------
// ShadowRoot オブジェクトを作成する
// ------------------------------------------------------------
var shadow_root = shadow_host.attachShadow( { mode:"open" } );
// ------------------------------------------------------------
// テンプレート内のコンテンツを複製し、ShadowRoot 内に配置する
// ------------------------------------------------------------
var content = template.content.cloneNode(true);
shadow_root.appendChild(content);
// ------------------------------------------------------------
// CSSStyleSheetList オブジェクトを取得する
// ------------------------------------------------------------
var sheet_list = shadow_root.styleSheets;
// ------------------------------------------------------------
// スタイルシートの総数を取得
// ------------------------------------------------------------
var num = sheet_list.length;
// ------------------------------------------------------------
// 出力テスト
// ------------------------------------------------------------
var i;
for(i=0;i < num;i++){
// CSSStyleSheet オブジェクトを取得する
var style_sheet = sheet_list[i];
// 出力テスト
console.log(style_sheet);
}
//-->
</script>
</body>
</html>
ShadowRoot の機能について
■ ShadowRoot の機能について
■ ShadowRoot のプロパティ一覧
プロパティ名 | 型 | 説明 |
host | Element | Shadow Host に該当する要素を取得する |
innerHTML | String | ShadowRoot 内のコンテンツを HTML 文字列で設定する |
styleSheets | StyleSheetList | CSSStyleSheet オブジェクトのリストを取得する |
activeElement | Element | ShadowRoot 内で、フォーカスを保持する要素を取得する |
■ ShadowRoot のメソッド一覧(一部抜粋)
メソッド名 | 説明 |
getElementById() | ID 属性からエレメントを取得する |
elementFromPoint() | クライアント座標を指定して、座標(点)と重なるエレメントを取得する |
getSelection() | Selection オブジェクトを取得する |
Element の追加機能について
■ Element の追加機能について
Element インターフェースには、以下の機能が追加されます。
■ Element の追加プロパティ一覧
プロパティ名 | 型 | 説明 |
shadowRoot | ShadowRoot | 作成した ShadowRoot オブジェクトを取得する |
<SLOT> 要素について
■ <SLOT> 要素について
<SLOT> 要素は、ShadowRoot 内で使用します。
<SLOT> 要素は、挿入ポイントの一種です。
■コンテント挿入ポイントについて
<SLOT> 要素には、Shadow Host 内に存在する要素を、代替表示できます。
ShadowRoot を作成すると、Shadow Host の子孫は非表示な状態となりますが、<SLOT> 要素を利用する事で、再び可視表示できるようになります。
■代替表示される要素について
代替表示される要素は、Shadow DOM としての恩恵はありません。
Shadow DOM ではなく、通常の DOM として動作します。
■ <SLOT> 要素の使用例
■ <SLOT> タグの記述例
<SLOT> 要素の記述例(ShadowRoot 内で使用する)
<slot name="aaa">
名前と一致する要素が存在しませんでした
</slot>
■ name 属性値について(Shadow ツリー内)
<SLOT> 要素の name 属性に、任意の名前を指定します。
■ slot 属性値について(Shadow ホスト内)
表示したい要素の slot 属性に、同じ名前を指定します。
同じ名前が存在すれば、その要素が代替表示されます。
同じ名前が複数存在する場合、順番にすべて表示されます。
見つからなかった場合、<SLOT> 要素の子孫が、そのまま表示されます。
既に別の場所で代替表示されている場合、2回目以降はマッチしません。
■ <SLOT> 要素の使用例
<SLOT> 要素を使って、コンテンツを表示する
<html>
<body>
<div id="my_shadow_host" >
<div slot="aaa" >私はホストAです</div>
<div slot="bbb" >私はホストBです</div>
</div>
<script type="text/javascript">
<!--
// ------------------------------------------------------------
// "my_shadow_host" という ID 属性のエレメントを取得する
// ------------------------------------------------------------
var shadow_host = document.getElementById("my_shadow_host");
// ------------------------------------------------------------
// ShadowRoot オブジェクトを作成する
// ------------------------------------------------------------
var shadow_root = shadow_host.attachShadow( { mode:"open" } );
// ------------------------------------------------------------
// HTML 文字列を指定して Shadow ツリーを構築する
// ------------------------------------------------------------
shadow_root.innerHTML =
'<div id="container">' +
' <slot name="aaa">Aが見つからなかった</slot> <br>' +
' <slot name="bbb">Bが見つからなかった</slot> <br>' +
' <slot name="ccc">Cが見つからなかった</slot>' +
'</div>';
// ------------------------------------------------------------
// ShadowRoot 内の content 要素を取得する
// ------------------------------------------------------------
var container = shadow_root.getElementById("container");
var slot_list = container.getElementsByTagName("slot");
var slot0 = slot_list[0];
var slot1 = slot_list[1];
var slot2 = slot_list[2];
// ------------------------------------------------------------
// slot 要素に現在表示されている DOM オブジェクトを取得する
// ------------------------------------------------------------
console.log( slot0.assignedNodes() );
console.log( slot1.assignedNodes() );
console.log( slot2.assignedNodes() );
//-->
</script>
</body>
</html>
■ <SLOT> 要素の機能について
■ <SLOT> 要素のプロパティ一覧
プロパティ名 | 型 | 説明 |
name | String | 代替表示したい Shadow Host 内の要素を、名前で指定する。 |
■ <SLOT> 要素のメソッド一覧
メソッド名 | 説明 |
assignedNodes() | 自身に現在表示されている DOM オブジェクトを、NodeList 形式で取得する。 代替表示に成功している場合、その要素が得られる。 |