Shadow DOM in JavaScript

Shadow DOM in JavaScript

Dieser Artikel erklärt das 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 &amp; 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>

Verständnis von Shadow DOM

Shadow DOM ist eine leistungsstarke Funktion des Web-Components-Standards, die die Kapselung von Stilen und DOM-Strukturen innerhalb von Komponenten ermöglicht. Diese Funktion verhindert, dass sich Stile und Skripte zwischen Komponenten und dem Hauptdokument gegenseitig stören.

Shadow DOM in JavaScript

Shadow DOM bietet eine Möglichkeit, einen begrenzten DOM-Baum zu erstellen, der mit einem normalen DOM-Element verknüpft ist. Dieser Schatten-Baum ist vom gesamten Dokument isoliert, sodass externe Stile und Skripte ihn nicht beeinflussen können und seine internen Stile und Skripte nicht nach außen dringen.

Wenn Sie beispielsweise eine benutzerdefinierte Schaltflächenkomponente mit Shadow DOM erstellen, beeinflussen deren Stile andere Elemente auf der Seite nicht. Ebenso führen Elemente mit dem gleichen Klassennamen nicht zu Konflikten.

Der reguläre HTML-Inhalt außerhalb des Shadow DOM wird als Light DOM bezeichnet.

Vorteile von Shadow DOM

  1. Kapselung

    • Das Shadow DOM trennt Stil und Funktionalität und verhindert Konflikte mit globalen Styles und Skripten.
  2. Wiederverwendbarkeit

    • Mit dem Shadow DOM erstellte Komponenten können in verschiedenen Projekten wiederverwendet werden, ohne dass Stilkonflikte auftreten.
  3. Wartbarkeit

    • Die Kapselung sorgt dafür, dass Logik und Stil einer Komponente in sich geschlossen sind, was das Debuggen und die Wartung erleichtert.

Erstellen von Shadow DOM

Um Shadow DOM zu verwenden, müssen Sie eine Schattenwurzel an ein HTML-Element anhängen. Hier ist ein einfaches Beispiel:.

1// Select the host element
2const hostElement = document.querySelector('#shadow-host');
3
4// Attach a shadow root
5const shadowRoot = hostElement.attachShadow({ mode: 'open' });

Erklärung

Dieser Code enthält die folgenden Elemente:.

  1. Host-Element

    • Ein reguläres DOM-Element, an das die Shadow-Root angehängt wird (in diesem Fall #shadow-host).
  2. Shadow-Root

    • Der Ursprung des Shadow-Trees, der mit attachShadow erstellt wird.
  3. Modus

    • Im Modus open kann externes JavaScript über element.shadowRoot auf die Shadow-Root zugreifen. Im Gegensatz dazu erlaubt der closed-Modus keinen Zugriff.

Styling innerhalb von Shadow DOM

Shadow DOM hat einen eigenen Stilbereich. Stile, die im Schattenbaum definiert sind, gelten nur für die Elemente innerhalb dieses Baums. Hier ist ein Beispiel:.

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

Auch wenn es im Hauptdokument widersprüchliche Styles gibt, beeinflussen diese den Absatz innerhalb des Shadow-Trees nicht.

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`;
  • Der Absatz innerhalb des Shadow DOM bleibt grün, während der äußere rot ist.

Ereignisse innerhalb des Shadow DOM

Ereignisse innerhalb des Shadow DOM ähneln normalen DOM-Ereignissen, können sich jedoch aufgrund der Kapselung in Bezug auf ihre Ausbreitung anders verhalten.

Hier ist ein Beispiel:.

 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});
  • Wenn der Button geklickt wird, werden beide Listener ausgelöst, was das Verhalten beim Event-Bubbling demonstriert.
  • Wenn ein Ereignis, das im Shadow DOM entsteht, zum Light DOM hochblubbert, wird das Ereignis-target auf das Host-Element statt auf die ursprüngliche Quelle umgeschrieben.
    • In diesem Beispiel ist event.target innerhalb des Shadow DOM das tatsächliche button-Element, aber außerhalb des Shadow DOM wird es durch das Host-div-Element ersetzt.

Shadow DOM und benutzerdefinierte Elemente

Shadow DOM und benutzerdefinierte Elemente sind zentrale Bestandteile von Web Components. Dies sind Technologien, die verwendet werden, um wiederverwendbare und gekapselte UI-Komponenten zu erstellen.

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

Das Hauptdokument enthält HTML wie dieses:.

1<my-card></my-card>
  • Durch die Verwendung von Shadow DOM in benutzerdefinierten Elementen können wiederverwendbare Komponenten erstellt werden, die resistent gegen Stilkonflikte sind. In diesem Code wird ein Tag namens my-card erstellt und mit der MyCard-Klasse verknüpft. Das <p>-Element innerhalb von my-card wird nicht von externen Styles beeinflusst und ist immer blau dargestellt.

Slots: Verteilung von Light DOM-Inhalten

Slots ermöglichen es, Inhalte des Light DOM in das Shadow DOM zu projizieren. Hier ist ein Beispiel:.

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

Das Hauptdokument enthält HTML wie dieses:.

1<my-element>
2    <h3 slot="header">Header Content</h1>
3    <p slot="content">Main Content</p>
4</my-element>
  • Das slot-Element innerhalb des Shadow DOM zeigt Light DOM-Inhalte an, die das entsprechende slot-Attribut besitzen.

Fazit

Shadow DOM ist ein wichtiges Werkzeug zum Erstellen robuster, wiederverwendbarer und wartbarer Webkomponenten. Durch die Kapselung von Stilen und Funktionen wird das Konfliktpotenzial reduziert und die Verwaltung des Codebestands vereinfacht.

Sie können den obigen Artikel mit Visual Studio Code auf unserem YouTube-Kanal verfolgen. Bitte schauen Sie sich auch den YouTube-Kanal an.

YouTube Video