Shadow DOM in JavaScript
Questo articolo spiega il Shadow DOM in JavaScript.
YouTube Video
javascript-html-shadow-dom.html
1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="UTF-8">
5 <title>JavaScript & HTML</title>
6 <style>
7 * {
8 box-sizing: border-box;
9 }
10
11 body {
12 margin: 0;
13 padding: 1em;
14 padding-bottom: 10em;
15 font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
16 background-color: #f7f9fc;
17 color: #333;
18 line-height: 1.6;
19 }
20
21 .container {
22 max-width: 800px;
23 margin: 0 auto;
24 padding: 1em;
25 background-color: #ffffff;
26 border: 1px solid #ccc;
27 border-radius: 10px;
28 box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
29 }
30
31 h1, h2 {
32 font-size: 1.2rem;
33 color: #007bff;
34 margin-top: 0.5em;
35 margin-bottom: 0.5em;
36 border-left: 5px solid #007bff;
37 padding-left: 0.6em;
38 background-color: #e9f2ff;
39 }
40
41 button {
42 display: block;
43 margin: 1em auto;
44 padding: 0.75em 1.5em;
45 font-size: 1rem;
46 background-color: #007bff;
47 color: white;
48 border: none;
49 border-radius: 6px;
50 cursor: pointer;
51 transition: background-color 0.3s ease;
52 }
53
54 button:hover {
55 background-color: #0056b3;
56 }
57
58 #output {
59 margin-top: 1em;
60 background-color: #1e1e1e;
61 color: #0f0;
62 padding: 1em;
63 border-radius: 8px;
64 min-height: 200px;
65 font-family: Consolas, monospace;
66 font-size: 0.95rem;
67 overflow-y: auto;
68 white-space: pre-wrap;
69 }
70
71 .highlight {
72 outline: 3px solid #ffc107; /* yellow border */
73 background-color: #fff8e1; /* soft yellow background */
74 transition: background-color 0.3s ease, outline 0.3s ease;
75 }
76
77 .active {
78 background-color: #28a745; /* green background */
79 color: #fff;
80 box-shadow: 0 0 10px rgba(40, 167, 69, 0.5);
81 transition: background-color 0.3s ease, box-shadow 0.3s ease;
82 }
83 </style>
84</head>
85<body>
86 <div class="container">
87 <h2>HTML Sample</h2>
88 <div id="content"></div>
89 <div id="shadow-host">Shadow Root Element</div>
90 <my-card></my-card>
91 </div>
92
93 <div class="container">
94 <h1>JavaScript Console</h1>
95 <button id="executeBtn">Execute</button>
96 <div id="output"></div>
97 </div>
98
99 <div>
100 <h2>Slot Sample</h2>
101 <my-element>
102 <h3 slot="header">Header Content</h1>
103 <p slot="content">Main Content</p>
104 </my-element>
105 </div>
106
107 <script>
108 // Override console.log to display messages in the #output element
109 (function () {
110 const originalLog = console.log;
111 console.log = function (...args) {
112 originalLog.apply(console, args);
113 const output = document.getElementById('output');
114 output.textContent += args.map(String).join(' ') + '\n';
115 };
116 })();
117
118 document.getElementById('executeBtn').addEventListener('click', () => {
119 // Prevent multiple loads
120 if (document.getElementById('externalScript')) return;
121
122 const script = document.createElement('script');
123 script.src = 'javascript-html-shadow-dom.js';
124 script.id = 'externalScript';
125 //script.onload = () => console.log('javascript-html-shadow-dom.js loaded and executed.');
126 //script.onerror = () => console.log('Failed to load javascript-html-shadow-dom.js.');
127 document.body.appendChild(script);
128 });
129 </script>
130</body>
131</html>
Comprendere il Shadow DOM
Il Shadow DOM
è una funzionalità potente dello standard dei Web Components, che consente l'incapsulamento degli stili e della struttura DOM all'interno dei componenti. Questa funzionalità impedisce interferenze tra stili e script dei componenti e il documento principale.
Shadow DOM
in JavaScript
Il Shadow DOM
offre un modo per creare un albero DOM limitato associato a un elemento DOM normale. Questo albero ombra è isolato dal documento generale: gli stili e gli script esterni non lo influenzano e i suoi stili e script interni non si propagano.
Ad esempio, se crei un componente personalizzato per un pulsante usando il Shadow DOM
, i suoi stili non interferiranno con altri elementi della pagina. Allo stesso modo, elementi con lo stesso nome di classe non entreranno in conflitto.
Il contenuto HTML regolare al di fuori del Shadow DOM
è chiamato Light DOM
.
Benefici del Shadow DOM
-
Incapsulamento
- Il
Shadow DOM
separa stile e funzionalità, prevenendo conflitti con stili e script globali.
- Il
-
Riutilizzabilità
- I componenti costruiti con il
Shadow DOM
possono essere riutilizzati in diversi progetti senza preoccuparsi di conflitti di stile.
- I componenti costruiti con il
-
Manutenibilità
- L'incapsulamento rende logica e stile del componente autonomi, facilitando il debugging e la manutenzione.
Creazione del Shadow DOM
Per usare il Shadow DOM
, è necessario collegare una radice ombra a un elemento HTML. Ecco un esempio semplice:.
1// Select the host element
2const hostElement = document.querySelector('#shadow-host');
3
4// Attach a shadow root
5const shadowRoot = hostElement.attachShadow({ mode: 'open' });
Spiegazione
Questo codice include i seguenti elementi:.
-
Elemento Host
- Un elemento DOM regolare a cui viene collegata la radice shadow (in questo caso,
#shadow-host
).
- Un elemento DOM regolare a cui viene collegata la radice shadow (in questo caso,
-
Shadow Root
- La radice dell'albero shadow creata tramite
attachShadow
.
- La radice dell'albero shadow creata tramite
-
Modalità
- In modalità
open
, JavaScript esterno può accedere alla shadow root tramiteelement.shadowRoot
. D'altro canto, la modalitàclosed
non consente l'accesso.
- In modalità
Stilizzazione all'interno del Shadow DOM
Il Shadow DOM
ha il proprio ambito di stile. Gli stili definiti all'interno dell'albero ombra si applicano solo agli elementi di quell'albero. Ecco un esempio:.
1// Add content to the shadow root
2shadowRoot.innerHTML = `
3 <style>
4 p {
5 color: green;
6 }
7 </style>
8 <p>Scoped style inside Shadow DOM.</p>
9`;
Anche se ci sono stili in conflitto nel documento principale, non influenzano il paragrafo all'interno dell'albero shadow.
1const content = document.getElementById('content');
2content.innerHTML = `
3 <style>
4 p {
5 color: red;
6 }
7 </style>
8 <p>This is in the main DOM.</p>
9`;
- Il paragrafo all'interno del
Shadow DOM
rimane verde, mentre quello esterno è rosso.
Eventi all'interno del Shadow DOM
Gli eventi all'interno del Shadow DOM
sono simili agli eventi del DOM regolare ma possono comportarsi diversamente in termini di propagazione a causa dell'incapsulamento.
Ecco un esempio:.
1// Add an event listener inside Shadow DOM
2shadowRoot.innerHTML = `
3 <div id="button-container">
4 <button id="shadow-button">Click Me</button>
5 </div>
6`;
7
8shadowRoot.querySelector('#shadow-button').addEventListener('click', (event) => {
9 console.log('Button : Button clicked inside Shadow DOM');
10 console.log(event.target);
11});
12
13shadowRoot.querySelector('#button-container').addEventListener('click', (event) => {
14 console.log('Container : Button clicked inside Shadow DOM');
15 console.log(event.target);
16});
17
18hostElement.addEventListener('click', (event) => {
19 console.log('Event bubbled to the host element');
20 console.log(event.target);
21});
22
23document.addEventListener('click', (event) => {
24 console.log('Document listener');
25 console.log(event.target);
26});
- Quando si clicca sul pulsante, entrambi i listener vengono attivati, dimostrando il comportamento della propagazione degli eventi.
- Quando un evento originato all'interno dello
Shadow DOM
si propaga verso ilLight DOM
, il suotarget
viene riscritto all'elemento host invece della sorgente originale.- In questo esempio,
event.target
all'interno delloShadow DOM
è effettivamente l'elementobutton
, ma al di fuori delloShadow DOM
viene sostituito con l'elemento hostdiv
.
- In questo esempio,
Shadow DOM
ed Elementi Personalizzati
Shadow DOM
e gli elementi personalizzati sono componenti chiave dei Web Components
. Sono tecnologie utilizzate per creare componenti UI riutilizzabili e incapsulati.
1class MyCard extends HTMLElement {
2 constructor() {
3 super();
4 const shadow = this.attachShadow({ mode: 'open' });
5 shadow.innerHTML = `
6 <style>
7 p {
8 color: blue;
9 }
10 </style>
11 <p>I'm inside shadow DOM</p>
12 `;
13 }
14}
15
16customElements.define('my-card', MyCard);
Il documento principale contiene HTML come questo:.
1<my-card></my-card>
- Utilizzando lo
Shadow DOM
all'interno degli elementi personalizzati, puoi creare componenti riutilizzabili resistenti ai conflitti di stile. In questo codice, viene creata una tag chiamatamy-card
e associata alla classeMyCard
. L'elemento<p>
all'interno dimy-card
non è influenzato dagli stili esterni ed è sempre visualizzato in blu.
Slot: Distribuire il contenuto del Light DOM
Gli slot permettono di proiettare il contenuto del Light DOM
dentro il Shadow DOM
. Ecco un esempio:.
1class MyElement extends HTMLElement {
2 constructor() {
3 super();
4 const shadow = this.attachShadow({ mode: 'open' });
5
6 shadow.innerHTML = `
7 <style>
8 .container {
9 border: 2px solid #ccc;
10 padding: 16px;
11 border-radius: 8px;
12 font-family: sans-serif;
13 }
14 .header {
15 font-size: 1.2em;
16 color: darkblue;
17 margin-bottom: 8px;
18 }
19 .content {
20 font-size: 1em;
21 color: #333;
22 }
23 </style>
24 <div class="container">
25 <div class="header">
26 <slot name="header"></slot>
27 </div>
28 <div class="content">
29 <slot name="content"></slot>
30 </div>
31 </div>
32 `;
33 }
34}
35
36customElements.define('my-element', MyElement);
Il documento principale contiene HTML come questo:.
1<my-element>
2 <h3 slot="header">Header Content</h1>
3 <p slot="content">Main Content</p>
4</my-element>
- L'elemento
slot
all'interno delShadow DOM
mostra il contenuto delLight DOM
che ha l'attributoslot
corrispondente.
Conclusione
Il Shadow DOM
è uno strumento fondamentale per costruire componenti web robusti, riutilizzabili e manutenibili. Incapsulando stili e funzionalità, riduce il rischio di conflitti e semplifica la gestione del codice.
Puoi seguire l'articolo sopra utilizzando Visual Studio Code sul nostro canale YouTube. Controlla anche il nostro canale YouTube.