1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
|
---
title: Usando 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">Un aspecto importante de los componentes Web es la encapsulación — ser capaz de mantener la estructura de marcado, estilo, y comportamiento oculto y separado de otro código en la página para que las diferentes partes no entre en conflicto, y el código pueda permanecer limpio y agradable. El API de DOM Shadow es un parte clave para esto, proporcionando una forma de enlazar un DOM oculto y separado a un elemento. Este artículo cubre los aspectos básicos para utilizar Shadow DOM.</p>
<div class="note">
<p><strong>Nota</strong>: Shadow DOM es soportado por defecto en Firefox (63 en adelante), Chrome, Opera, y Safari. Edge también está trabajando en una implemetanción.</p>
</div>
<h2 id="Vista_de_alto_nivel">Vista de alto nivel</h2>
<p>Este artículo asume que usted está familiarizado con el concepto de <a href="/en-US/docs/Web/API/Document_Object_Model/Introduction">DOM (Document Object Model)</a> — una estructura en forma de arbol de nodos conectados que representan los diferentes elementos y cadenas de texto que aparecen en un documento de marcado (generalmente un documento HTML en el caso de documentos web). Como ejemplo, considere el siguiente fragmento HTML:</p>
<pre class="brush: html notranslate"><!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>Este fragmento produce la siguientre estructura de 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 permite adjuntar arboles DOM ocultos a elementos en el arbol DOM regular — este arbol shadow DOM comienza con un elemento <strong>shadow root,</strong> debajo del cual se puede adjuntar cualquier elemento que desee, de la misma manera que el DOM normal.</p>
<p><img alt="" src="https://mdn.mozillademos.org/files/15788/shadow-dom.png" style="height: 543px; width: 1138px;"></p>
<p>Hay algunos conceptos de Shadow DOM que deben ser tomados en cuenta:</p>
<ul>
<li><strong>Shadow host</strong>: El nodo regular del DOM al que es atado el shadow DOM.</li>
<li><strong>Shadow tree</strong>: El arbol DOM dentro del shadow DOM.</li>
<li><strong>Shadow boundary</strong>: El punto en el que el shadow DOM termina y el DOM regular comienza.</li>
<li><strong>Shadow root</strong>: El nodo raiz del arbol Shadow.</li>
</ul>
<p>Puede manipular los nodos del 'shadow DOM' de la misma manera que los nodos del arbol DOM regular. Por ejemplo, agregando hijos o estableciendo atributos, dando estilo a nodos individuales utilizando element.style.foo, o agregando estilo a todo el árbol de 'shadow DOM' dentro del elemento <style>. La diferencia es que nada del código dentro de un 'shadow DOM' puede afectar a nada fuera de él, lo que permite una encapsulación práctica.</p>
<p>Cabe destacar que el shadow DOM no es algo nuevo — los exploradores lo han usado por un largo tiempo para encapsular la estructura interna de un elemento. Piensa por ejemplo en un elemento {{htmlelement("video")}}, con los controles predeterminados del explorador a la vista. Todo lo que ves en el DOM es el elemento <code><video></code>, pero este contiene una serie de botones y otros controles dentro de su shadow DOM. Las especificaciones del shadow DOM fueron hechas para que seas capaz de manipular el shadow DOM de tus elementos personalizados.</p>
<h2 id="Uso_básico">Uso básico</h2>
<p>Puede adjuntar un 'shadow root' a cualquier elemento utilizando el método {{domxref ("Element.attachShadow ()")}}. Éste toma como parámetro un objeto que contiene una propiedad — modo — con dos posibles valores: 'open' o 'closed'.</p>
<pre class="brush: js notranslate">let shadow = elementRef.attachShadow({mode: 'open'});
let shadow = elementRef.attachShadow({mode: 'closed'});</pre>
<p><code>open</code> siginifica que puede acceder al shadow DOM usando JavaScript en el contexto principal de la página. Por ejemplo, usando la propiedad {{domxref("Element.shadowRoot")}}:</p>
<pre class="brush: js notranslate">let myShadowDom = myCustomElem.shadowRoot;</pre>
<p>If you attach a shadow root to a custom element with <code>mode: closed</code> set, you won't be able to access the shadow DOM from the outside — <code>myCustomElem.shadowRoot</code> returns <code>null</code>. This is the case with built in elements that contain shadow DOMs, such as <code><video></code>.</p>
<div class="note">
<p><strong>Note</strong>: As <a href="https://blog.revillweb.com/open-vs-closed-shadow-dom-9f3d7427d1af">this blog post shows</a>, it is actually fairly easy to work around closed shadow DOMs, and the hassle to completely hide them is often more than it's worth.</p>
</div>
<p>If you are attaching a shadow DOM to a custom element as part of its constructor (by far the most useful application of the shadow DOM), you would use something like this:</p>
<pre class="brush: js notranslate">let shadow = this.attachShadow({mode: 'open'});</pre>
<p>When you've attached a shadow DOM to an element, manipulating it is a matter of just using the same DOM APIs as you use for the regular DOM manipulation:</p>
<pre class="brush: js notranslate">var para = document.createElement('p');
shadow.appendChild(para);
// etc.</pre>
<h2 id="Working_through_a_simple_example">Working through a simple example</h2>
<p>Now let's walk through a simple example to demonstrate the shadow DOM in action inside a custom element — <code><a href="https://github.com/mdn/web-components-examples/tree/master/popup-info-box-web-component"><popup-info-box></a></code> (see a <a href="https://mdn.github.io/web-components-examples/popup-info-box-web-component/">live example</a> also). This takes an image icon and a text string, and embeds the icon into the page. When the icon is focused, it displays the text in a pop up information box to provide further in-context information. To begin with, in our JavaScript file we define a class called <code>PopUpInfo</code>, which extends <code>HTMLElement</code>:</p>
<pre class="brush: js notranslate">class PopUpInfo extends HTMLElement {
constructor() {
// Always call super first in constructor
super();
// write element functionality in here
...
}
}</pre>
<p>Inside the class definition we define the element's constructor, which defines all the functionality the element will have when an instance of it is instantiated.</p>
<h3 id="Creating_the_shadow_root">Creating the shadow root</h3>
<p>We first attach a shadow root to the custom element:</p>
<pre class="brush: js notranslate">// Create a shadow root
var shadow = this.attachShadow({mode: 'open'});</pre>
<h3 class="brush: js" id="Creating_the_shadow_DOM_structure">Creating the shadow DOM structure</h3>
<p class="brush: js">Next, we use some DOM manipulation to create the element's internal shadow DOM structure:</p>
<pre class="brush: js notranslate">// 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="Styling_the_shadow_DOM">Styling the shadow DOM</h3>
<p class="brush: js">After that we create a {{htmlelement("style")}} element and populate it with some CSS to style it:</p>
<pre class="brush: js notranslate">// 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="Attaching_the_shadow_DOM_to_the_shadow_root">Attaching the shadow DOM to the shadow root</h3>
<p>The final step is to attach all the created elements to the shadow root:</p>
<pre class="brush: js notranslate">// attach the created elements to the shadow dom
shadow.appendChild(style);
shadow.appendChild(wrapper);
wrapper.appendChild(icon);
wrapper.appendChild(info);</pre>
<h3 id="Using_our_custom_element">Using our custom element</h3>
<p>Once the class is defined, using the element is as simple as defining it, and putting it on the page, as explained in <a href="/en-US/docs/Web/Web_Components/Using_custom_elements">Using custom elements</a>:</p>
<pre class="brush: js notranslate">// Define the new element
customElements.define('popup-info', PopUpInfo);</pre>
<pre class="brush: html notranslate"><<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>
<h2 id="See_also">See also</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>
|