web-dev-qa-db-fra.com

Est-il possible d'accéder aux éléments du Shadow DOM via le document parent?

Cette question est davantage destinée aux éléments DOM créés par l'utilisateur, mais pour l'accessibilité, j'utiliserai le type d'entrée date pour cette question:

Disons par exemple que j'ai une entrée date sur ma page. Avec quelques bits édités, le balisage DOM fantôme pour cela (en utilisant Chrome) ressemble à quelque chose comme:

<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>

Les méthodes et propriétés associées à l'entrée date ne semblent pas du tout faire référence au DOM fantôme ( JSFiddle ), donc je me demandais comment (le cas échéant) ces éléments du DOM fantôme être accessible?

29
James Donnelly

Comme @ int32_t l'a indiqué correctement, le DOM fantôme, par définition, est un moyen de remplir un nœud avec le DOM que vous souhaitez masquer aux sources externes ( Encapsulation ). Le fait est que vous, en tant qu'auteur du composant, pouvez choisir exactement quelles parties seront exposées à l'extérieur de CSS ou JavaScript et lesquelles ne le seront pas.

Malheureusement, vous ne pouvez pas créer une interface JavaScript publique pour votre Shadow DOM sans utiliser une autre spécification de bord de fuite appelée éléments personnalisés . Si vous choisissez de le faire, c'est aussi simple que d'ajouter des méthodes publiques personnalisées au prototype de votre élément. À partir de ceux-ci, vous pouvez accéder aux composants internes de votre Shadow DOM (voir le troisième exemple ici ).

Vous pouvez cependant exposer des crochets pour que CSS accède aux composants internes de votre Shadow DOM sans utiliser d'éléments personnalisés. Il y a deux façons de procéder:

  1. Pseudo-éléments
  2. Variables CSS

Pseudo-éléments

Chrome et Firefox exposent certaines parties de leur Shadow DOM au CSS via des pseudo-éléments spéciaux. Voici votre exemple de l'entrée date avec l'ajout d'une règle CSS qui ne s'applique qu'à la partie numérique du champ de date grâce à l'utilisation du -webkit-datetime-edit Fourni par Chrome pseudo-élément.

Voici une liste partielle des pseudo-éléments WebKit disponibles. Vous pouvez également simplement activer l'option Show Shadow DOM Dans DevTools et rechercher des attributs nommés pseudo.

Les auteurs de composants peuvent également créer leurs propres pseudo-éléments pour exposer des parties de leur DOM fantôme (voir le 2ème exemple ici ).

Variables CSS

Une méthode encore meilleure consiste à utiliser les variables CSS, que vous pouvez activer avec Enable experimental WebKit features Dans about:flags Dans Chrome. Ensuite, vérifiez ce violon qui utilise des variables CSS pour communiquer au DOM Shadow quelle couleur il doit utiliser pour son "thème".

18
CletusW

Maintenant (2016), vous pouvez accéder aux éléments open créés par l'utilisateur shadow DOM (mais pas de shadow DOM créé par l'agent utilisateur) en utilisant la méthode querySelector à la racine du 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

Vous ne pouvez pas accéder au contenu de Shadow DOM à partir de scripts en dehors du Shadow DOM. L'encapsulation est l'objectif du DOM fantôme.

4
int32_t

Oui. Il vous suffit d'appeler .root ou .shadowRoot. Voici un exemple,

document.getElementById('itemId').root 

Vous n'obtiendrez pas l'élément dom ombre sans l'élément innerText ou innerHTML sur l'élément dom parent.

1
pravchuk