Shadow DOM in JavaScript
Dit artikel legt uit wat de Shadow DOM in JavaScript is.
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>Begrijpen van Shadow DOM
Shadow DOM is een krachtige functie van de Web Components-standaard die encapsulatie van stijlen en DOM-structuur binnen componenten mogelijk maakt. Deze functie voorkomt interferentie van stijlen en scripts tussen componenten en het hoofddocument.
Shadow DOM in JavaScript
Shadow DOM biedt een manier om een gescopeerde DOM-boom te maken die is gekoppeld aan een regulier DOM-element. Deze shadow tree is geïsoleerd van het algemene document, waarbij externe stijlen en scripts geen invloed hebben en interne stijlen en scripts niet uitlekken.
Bijvoorbeeld, als u een aangepast knopcomponent maakt met Shadow DOM, zullen de stijlen ervan geen interferentie veroorzaken met andere elementen op de pagina. Evenzo zullen elementen met dezelfde classnaam geen conflicten veroorzaken.
De gewone HTML-inhoud buiten de Shadow DOM wordt aangeduid als de Light DOM.
Voordelen van Shadow DOM
-
Insluiting (Encapsulatie)
- De
Shadow DOMscheidt stijl en functionaliteit, waardoor conflicten met globale stijlen en scripts worden voorkomen.
- De
-
Hergebruikbaarheid
- Componenten die met de
Shadow DOMzijn gebouwd, kunnen opnieuw worden gebruikt in verschillende projecten zonder zich zorgen te hoeven maken over stijlconflicten.
- Componenten die met de
-
Onderhoudbaarheid
- Encapsulatie zorgt ervoor dat de logica en stijl van een component op zichzelf staan, waardoor het debuggen en onderhouden eenvoudiger wordt.
Het maken van Shadow DOM
Om Shadow DOM te gebruiken, moet u een shadow root koppelen aan een HTML-element. Hier is een eenvoudig voorbeeld:.
1// Select the host element
2const hostElement = document.querySelector('#shadow-host');
3
4// Attach a shadow root
5const shadowRoot = hostElement.attachShadow({ mode: 'open' });Uitleg
Deze code bevat de volgende elementen:.
-
Hostelement
- Een normaal DOM-element waaraan de shadow root wordt gekoppeld (in dit geval,
#shadow-host).
- Een normaal DOM-element waaraan de shadow root wordt gekoppeld (in dit geval,
-
Shadow Root
- De root van de shadow-tree die is aangemaakt met
attachShadow.
- De root van de shadow-tree die is aangemaakt met
-
Modus
- In de
openmodus kan externe JavaScript toegang krijgen tot de shadow root viaelement.shadowRoot. Aan de andere kant staat declosedmodus geen toegang toe.
- In de
Styling binnen Shadow DOM
Shadow DOM heeft zijn eigen stylingbereik. Stijlen die zijn gedefinieerd binnen de shadow tree zijn alleen van toepassing op de elementen binnen die tree. Hier is een voorbeeld:.
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`;Zelfs als er conflicterende stijlen in het hoofd-document zijn, hebben deze geen invloed op de paragraaf in de shadow-tree.
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`;- De paragraaf in de
Shadow DOMblijft groen, terwijl de externe rood is.
Gebeurtenissen binnen de Shadow DOM
Gebeurtenissen binnen de Shadow DOM lijken op gewone DOM-gebeurtenissen maar kunnen anders gedragen qua voortplanting vanwege encapsulatie.
Hier is een voorbeeld:.
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});- Wanneer op de knop wordt geklikt, worden beide luisteraars geactiveerd, wat het gedrag van event bubbling demonstreert.
- Wanneer een gebeurtenis die afkomstig is uit de
Shadow DOMomhoog bubbelt naar deLight DOM, wordt detargetvan het evenement herschreven naar het host-element in plaats van de oorspronkelijke bron.- In dit voorbeeld is
event.targetbinnen deShadow DOMdaadwerkelijk hetbutton-element, maar buiten deShadow DOMwordt het vervangen door het hostdiv-element.
- In dit voorbeeld is
Shadow DOM en Aangepaste Elementen
Shadow DOM en aangepaste elementen zijn kerncomponenten van Web Components. Het zijn technologieën die worden gebruikt om herbruikbare en ingekapselde UI-componenten te maken.
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);Het hoofd-document bevat HTML zoals deze:.
1<my-card></my-card>- Door
Shadow DOMte gebruiken binnen aangepaste elementen, kun je herbruikbare componenten bouwen die bestand zijn tegen stijlconflicten. In deze code wordt een tag met de naammy-cardgemaakt en gekoppeld aan deMyCard-klasse. Het<p>-element binnenmy-cardwordt niet beïnvloed door externe stijlen en wordt altijd in het blauw weergegeven.
Slots: Verdelen van Light DOM-inhoud
Met slots kun je Light DOM-inhoud projecteren in de Shadow DOM. Hier is een voorbeeld:.
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);Het hoofd-document bevat HTML zoals deze:.
1<my-element>
2 <h3 slot="header">Header Content</h1>
3 <p slot="content">Main Content</p>
4</my-element>- Het
slot-element binnen deShadow DOMtoontLight DOM-inhoud met het bijbehorendeslot-attribuut.
Conclusie
Shadow DOM is een essentieel hulpmiddel voor het bouwen van robuuste, herbruikbare en onderhoudbare webcomponenten. Door stijlen en functionaliteit te encapsuleren, vermindert het de kans op conflicten en vereenvoudigt het het beheer van de codebase.
Je kunt het bovenstaande artikel volgen met Visual Studio Code op ons YouTube-kanaal. Bekijk ook het YouTube-kanaal.