Shadow DOM i JavaScript

Shadow DOM i JavaScript

Den här artikeln förklarar Shadow DOM i 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>

Förstå Shadow DOM

Shadow DOM är en kraftfull funktion inom Web Components-standarden som möjliggör inkapsling av stilar och DOM-struktur inom komponenter. Denna funktion förhindrar störningar mellan stilar och skript i komponenter och huvuddokumentet.

Shadow DOM i JavaScript

Shadow DOM ger ett sätt att skapa ett avgränsat DOM-träd kopplat till ett vanligt DOM-element. Detta skuggträd är isolerat från det övergripande dokumentet, där externa stilar och skript inte påverkar det och dess interna stilar och skript inte läcker ut.

Till exempel, om du skapar en anpassad knappkomponent med Shadow DOM, kommer dess stilar inte att störa andra element på sidan. På samma sätt kommer element med samma klassnamn inte att orsaka konflikter.

Vanligt HTML-innehåll utanför Shadow DOM kallas för Light DOM.

Fördelar med Shadow DOM

  1. Inkapsling

    • Shadow DOM separerar stil och funktionalitet, vilket förhindrar konflikter med globala stilar och skript.
  2. Återanvändbarhet

    • Komponenter byggda med Shadow DOM kan återanvändas i olika projekt utan att man behöver oroa sig för stilkonflikter.
  3. Underhållbarhet

    • Inkapsling gör komponentens logik och stil självständiga, vilket gör felsökning och underhåll enklare.

Skapa Shadow DOM

För att använda Shadow DOM måste du fästa en skuggrot till ett HTML-element. Här är ett enkelt exempel:.

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

Förklaring

Den här koden innehåller följande element:.

  1. Värdelement

    • Ett vanligt DOM-element där shadow root är kopplat (i det här fallet, #shadow-host).
  2. Shadow Root

    • Roten av skuggträdet som skapas med hjälp av attachShadow.
  3. Läge

    • I open-läge kan extern JavaScript komma åt shadow root via element.shadowRoot. Å andra sidan tillåter inte closed-läget åtkomst.

Stilhantering inom Shadow DOM

Shadow DOM har sitt eget stilområde. Stilar som definieras inom skuggan trädet gäller endast för elementen inom det trädet. Här är ett exempel:.

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

Även om det finns konflikterande stilar i huvuddokumentet påverkar de inte paragrafen inuti 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`;
  • Paragrafen inuti Shadow DOM förblir grön, medan den utanför är röd.

Händelser inom Shadow DOM

Händelser inom Shadow DOM liknar vanliga DOM-händelser men kan bete sig annorlunda vad gäller spridning på grund av kapsling.

Här är ett exempel:.

 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});
  • När knappen klickas på aktiveras båda lyssnarna, vilket demonstrerar beteendet för händelsebubbling.
  • När en händelse som uppstår inne i Shadow DOM bubblar upp till Light DOM, skrivs händelsens target om till värdelementet istället för den ursprungliga källan.
    • I det här exemplet är event.target inne i Shadow DOM det faktiska button-elementet, men utanför Shadow DOM ersätts det med värd-div-elementet.

Shadow DOM och anpassade element

Shadow DOM och anpassade element är nyckelkomponenter i Web Components. De är teknologier som används för att skapa återanvändbara och kapslade UI-komponenter.

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

Huvuddokumentet innehåller HTML som detta:.

1<my-card></my-card>
  • Genom att använda Shadow DOM inom anpassade element kan du skapa återanvändbara komponenter som är motståndskraftiga mot stilkonflikter. I den här koden skapas en tagg med namnet my-card och kopplas till klassen MyCard. <p>-elementet inuti my-card påverkas inte av externa stilar och visas alltid i blått.

Slots: Fördelning av Light DOM-innehåll

Slots gör det möjligt att projicera Light DOM-innehåll in i Shadow DOM. Här är ett exempel:.

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

Huvuddokumentet innehåller HTML som detta:.

1<my-element>
2    <h3 slot="header">Header Content</h1>
3    <p slot="content">Main Content</p>
4</my-element>
  • slot-elementet inuti Shadow DOM visar det Light DOM-innehåll som har motsvarande slot-attribut.

Slutsats

Shadow DOM är ett viktigt verktyg för att bygga robusta, återanvändbara och underhållbara webbkomponenter. Genom att kapsla in stilar och funktioner minskar det risken för konflikter och förenklar hantering av kodbasen.

Du kan följa med i artikeln ovan med hjälp av Visual Studio Code på vår YouTube-kanal. Vänligen kolla även in YouTube-kanalen.

YouTube Video