Shadow DOM in JavaScript

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 &amp; HTML</title>
  6  <style>
  7    * {
  8        box-sizing: border-box;
  9    }
 10
 11    body {
 12        margin: 0;
 13        padding: 1em;
 14        padding-bottom: 4em;
 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

  1. Insluiting (Encapsulatie)

    • De Shadow DOM scheidt stijl en functionaliteit, waardoor conflicten met globale stijlen en scripts worden voorkomen.
  2. Hergebruikbaarheid

    • Componenten die met de Shadow DOM zijn gebouwd, kunnen opnieuw worden gebruikt in verschillende projecten zonder zich zorgen te hoeven maken over stijlconflicten.
  3. 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:.

  1. Hostelement

    • Een normaal DOM-element waaraan de shadow root wordt gekoppeld (in dit geval, #shadow-host).
  2. Shadow Root

    • De root van de shadow-tree die is aangemaakt met attachShadow.
  3. Modus

    • In de open modus kan externe JavaScript toegang krijgen tot de shadow root via element.shadowRoot. Aan de andere kant staat de closed modus geen toegang toe.

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 DOM blijft 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 van oorsprong is in de.
    • In dit voorbeeld is de Shadow DOM het eigenlijke Button DOM element, maar buiten de Shadow DOM wordt het vervangen door het host.

Schaduw DOM en aangepaste elementen

Schaduw DOM en aangepaste elementen zijn de belangrijkste componenten van Web Componenten. Het zijn technologieën die worden gebruikt om herbruikbare en ingekapselde UI componenten te creëren.

 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 gebruik te maken van Shadow DOM. In deze code wordt een tag met de naam "Mijn kaart" gemaakt en geassocieerd met de klasse "MyCard". Het element in mijn kaart wordt niet beïnvloed door externe stijlen en wordt altijd in 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 de Shadow DOM toont Light DOM-inhoud met het bijbehorende slot-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.

YouTube Video