web-dev-qa-db-ja.com

親ドキュメントを介してShadow DOM要素にアクセスすることは可能ですか?

この質問は、ユーザーが作成したシャドウDOM要素を対象としていますが、アクセシビリティのために、この質問にはdate入力タイプを使用します。

たとえば、ページにdate入力があるとします。いくつかのビットを編集すると、この(Chromeを使用した)シャドウDOMマークアップは次のようになります。

<input type="date">
    #document-fragment
        <div pseudo="-webkit-datetime-edit">
            <div pseudo="-webkit-datetime-edit-fields-wrapper">
                <span role="spinbutton">dd</span>
                <div pseudo="-webkit-datetime-edit-text">/</div>
                <span role="spinbutton">mm</span>
                <div pseudo="-webkit-datetime-edit-text">/</div>
                <span role="spinbutton">yyyy</span>
            </div>
        </div>
        <div></div>
        <div pseudo="-webkit-calendar-picker-indicator"></div>

date入力に関連付けられたメソッドとプロパティは、シャドウDOMをまったく参照していないように見えます( JSFiddle )。アクセスされる?

29
James Donnelly

@ int32_tが正しく示しているように、Shadow DOMは定義上、外部ソースから非表示にするDOMでノードを埋める方法です( Encapsulation )。ポイントは、コンポーネントの作成者として、CSSまたはJavaScriptの外部に公開する部分と公開しない部分を正確に選択できることです。

残念ながら、 Custom Elements と呼ばれる別の最先端の仕様を使用せずに、Shadow DOMへのパブリックJavaScriptインターフェイスを作成することはできません。それを選択する場合、カスタムパブリックメソッドを要素のプロトタイプに追加するのと同じくらい簡単です。これらからShadow DOMの内部にアクセスできます(3番目の例を参照してください here )。

ただし、CSSのフックを公開して、カスタム要素を使用せずにShadow DOMの内部にアクセスできます。それを行うには2つの方法があります。

  1. 擬似要素
  2. CSS変数

擬似要素

ChromeとFirefoxは、シャドウDOMの特定の部分を特別な擬似要素を介してCSSに公開します。 こちら Chromeが提供する-webkit-datetime-edit pseudoを使用して日付フィールドの数値部分にのみ適用されるCSSルールを追加したdate入力の例-素子。

Here's 利用可能なWebKit擬似要素の部分的なリスト。 DevToolsでShow Shadow DOMオプションを有効にして、pseudoという名前の属性を探すこともできます。

コンポーネントの作成者は、独自の疑似要素を作成してShadow DOMの一部を公開することもできます(2番目の例 here を参照)。

CSS変数

さらに良い方法は、CSS変数を使用することです。これは、ChromeのEnable experimental WebKit featuresabout:flagsで有効にできます。次に、CSS変数を使用してShadow DOMと「テーマ」に使用する色を通信する this fiddle を確認します。

18
CletusW

現在(2016)、Shadow DOMルートでquerySelectorメソッドを使用して、open ser-created shadow DOM要素にアクセスできます(ただし、user agentが作成したshadow DOMはありません!)。

<body>
    <div id="container"></div>
    <script>
        //Shadow Root
        ̶v̶a̶r̶ ̶r̶o̶o̶t̶ ̶=̶ ̶c̶o̶n̶t̶a̶i̶n̶e̶r̶.̶c̶r̶e̶a̶t̶e̶S̶h̶a̶d̶o̶w̶R̶o̶o̶t̶(̶)̶
        //new syntax:
        var root = container.attachShadow( { mode: "open" } )

        //Inside element
        var span = document.createElement( "span" )
        span.textContent = "i'm inside the Shadow DOM"
        span.id = "inside"
        root.appendChild( span )

        //Access inside element
        console.log( container.shadowRoot.querySelector( "#inside" ) )
    </script>
</body>
//Shadow Root
var root = container.createShadowRoot()

//Inside element
var span = document.createElement( "span" )
span.textContent = "i'm inside the Shadow DOM"
span.id = "inside"
root.appendChild( span )

//Access inside element
function get() 
{
  alert( container.shadowRoot.querySelector( "#inside" ).id )
}
<!DOCTYPE html>
<html>
<head>
    <title></title>
        <meta charset="utf-8" />
</head>
<body>
        <div id="container"></div>
    <button onclick="get()">Get</button>
        <script>
        </script>
</body>
</html>
16
Supersharp

Shadow DOMの外部のスクリプトからShadow DOMのコンテンツにアクセスすることはできません。カプセル化はShadow DOMの目的です。

4
int32_t

はい。 .rootまたは.shadowRootを呼び出すだけです。以下に例を示します。

document.getElementById('itemId').root 

親dom要素のinnerTextまたはinnerHTMLなしでは、shadow dom要素は取得されません。

1
pravchuk