Shadow DOM i JavaScript

Shadow DOM i JavaScript

Denne artikkelen forklarer 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>

Forståelse av Shadow DOM

Shadow DOM er en kraftig funksjon i Web Components-standarden som muliggjør kapsling av stiler og DOM-struktur innenfor komponenter. Denne funksjonen forhindrer interferens av stiler og skript mellom komponenter og hoveddokumentet.

Shadow DOM i JavaScript

Shadow DOM gir en måte å opprette et avgrenset DOM-tre tilknyttet et vanlig DOM-element. Dette skyggedokumentet er isolert fra det totale dokumentet, slik at eksterne stiler og skript ikke påvirker det, og interne stiler og skript lekker ikke ut.

For eksempel, hvis du lager en tilpasset knappkomponent ved hjelp av Shadow DOM, vil dens stiler ikke forstyrre andre elementer på siden. På samme måte vil elementer med samme klassenavn ikke komme i konflikt.

Vanlig HTML-innhold utenfor Shadow DOM kalles Light DOM.

Fordeler med Shadow DOM

  1. Innkapsling

    • Shadow DOM skiller stil og funksjonalitet, og forhindrer konflikter med globale stiler og skript.
  2. Gjenbrukbarhet

    • Komponenter bygget med Shadow DOM kan gjenbrukes på ulike prosjekter uten å bekymre seg for stilkonflikter.
  3. Vedlikeholdbarhet

    • Innkapsling gjør komponentens logikk og stil selvstendig, noe som gjør feilsøking og vedlikehold enklere.

Opprette Shadow DOM

For å bruke Shadow DOM, må du knytte en skyggerot til et HTML-element. Her er et enkelt eksempel:.

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

Forklaring

Denne koden inneholder følgende elementer:.

  1. Vertselement

    • Et vanlig DOM-element som shadow root er festet til (i dette tilfellet, #shadow-host).
  2. Shadow Root

    • Roten til skyggetreet, opprettet med attachShadow.
  3. Modus

    • I open-modus kan ekstern JavaScript få tilgang til shadow root via element.shadowRoot. På den andre siden tillater ikke lukket modus tilgang.

Stilsetting innenfor Shadow DOM

Shadow DOM har sitt eget stilomfang. Stiler definert i shadow-treet gjelder kun for elementer innenfor det treet. Her er et eksempel:.

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

Selv om det finnes stilkonflikter i hoveddokumentet, påvirker de ikke paragrafen inne i shadow-treet.

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 inne i Shadow DOM forblir grønn, mens den eksterne er rød.

Hendelser i Shadow DOM

Hendelser i Shadow DOM ligner vanlige DOM-hendelser, men kan oppføre seg annerledes med hensyn til propagasjon på grunn av kapsling.

Her er et eksempel:.

 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 klikkes, aktiveres begge lytterne, noe som demonstrerer oppførselen til hendelsesbobling.
  • Når en hendelse som starter inne i Shadow DOM bobler opp til Light DOM, blir hendelsens target omskrevet til vertselementet i stedet for den opprinnelige kilden.
    • I dette eksempelet er event.target inne i Shadow DOM det faktiske button-elementet, men utenfor Shadow DOM blir det erstattet med vertselementet div.

Shadow DOM og egendefinerte elementer

Shadow DOM og egendefinerte elementer er nøkkelkomponenter i Web Components. De er teknologier som brukes til å lage gjenbrukbare og innkapslede 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);

Hoveddokumentet inneholder HTML som dette:.

1<my-card></my-card>
  • Ved å bruke Shadow DOM inne i egendefinerte elementer kan du lage gjenbrukbare komponenter som er motstandsdyktige mot stilkonflikter. I denne koden opprettes en tagg kalt my-card og knyttes til klassen MyCard. Elementet <p> inne i my-card påvirkes ikke av eksterne stiler og vises alltid i blått.

Slots: Distribuere Light DOM-innhold

Slots lar deg projisere Light DOM-innhold inn i Shadow DOM. Her er et eksempel:.

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

Hoveddokumentet inneholder HTML som dette:.

1<my-element>
2    <h3 slot="header">Header Content</h1>
3    <p slot="content">Main Content</p>
4</my-element>
  • slot-elementet inne i Shadow DOM viser Light DOM-innhold som har tilsvarende slot-attributt.

Konklusjon

Shadow DOM er et viktig verktøy for å bygge robuste, gjenbrukbare og vedlikeholdbare webkomponenter. Ved å kapsle inn stiler og funksjonalitet reduserer den potensialet for konflikter og forenkler styring av kodebasen.

Du kan følge med på artikkelen ovenfor ved å bruke Visual Studio Code på vår YouTube-kanal. Vennligst sjekk ut YouTube-kanalen.

YouTube Video