Shadow DOM sa JavaScript

Shadow DOM sa JavaScript

Ipinaliwanag ng artikulong ito ang Shadow DOM sa 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>

Pag-unawa sa Shadow DOM

Ang Shadow DOM ay isang makapangyarihang tampok ng pamantayan ng Web Components na nagbibigay-daan sa encapsulation ng mga estilo at istruktura ng DOM sa loob ng mga komponent. Pinipigilan ng tampok na ito ang pagkakaroon ng interference sa pagitan ng mga estilo at script ng mga komponent at ng pangunahing dokumento.

Shadow DOM sa JavaScript

Nagbibigay ang Shadow DOM ng paraan upang makagawa ng scoped na DOM tree na nauugnay sa isang regular na DOM element. Ang shadow tree na ito ay hiwalay sa kabuuang dokumento, kung saan ang mga panlabas na estilo at script ay hindi nakakaimpluwensya rito, at ang mga panloob na estilo at script nito ay hindi rin tumatagas palabas.

Halimbawa, kung gagawa ka ng isang custom na button component gamit ang Shadow DOM, ang mga estilo nito ay hindi makakaapekto sa ibang mga elemento sa pahina. Sa parehong paraan, ang mga elemento na may parehong pangalan ng klase ay hindi magkakaroon ng salungatan.

Ang karaniwang HTML na nilalaman sa labas ng Shadow DOM ay tinatawag na Light DOM.

Mga Benepisyo ng Shadow DOM

  1. Encapsulation

    • Ang Shadow DOM ay naghihiwalay ng estilo at functionality, kaya naiiwasan ang banggaan sa mga global na style at script.
  2. Reusability

    • Ang mga component na ginawa gamit ang Shadow DOM ay maaaring magamit muli sa iba’t ibang proyekto nang hindi nag-aalala sa pagkakabangga ng mga style.
  3. Maintainability

    • Ang encapsulation ay ginagawang self-contained ang lohika at style ng component, kaya mas madali ang pag-debug at pag-maintain.

Paglikha ng Shadow DOM

Upang magamit ang Shadow DOM, kailangan mong mag-attach ng shadow root sa isang elemento ng HTML. Narito ang isang simpleng halimbawa:.

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

Paliwanag

Ang code na ito ay naglalaman ng mga sumusunod na elemento:.

  1. Host Element

    • Isang karaniwang DOM element kung saan nakakabit ang shadow root (sa kasong ito, #shadow-host).
  2. Shadow Root

    • Ang ugat ng shadow tree na ginawa gamit ang attachShadow.
  3. Mode

    • Sa open mode, maaaring i-access ng external na JavaScript ang shadow root gamit ang element.shadowRoot. Sa kabilang banda, ang closed mode ay hindi nagpapahintulot ng pag-access.

Pag-istilo sa loob ng Shadow DOM

Ang Shadow DOM ay may sarili nitong saklaw ng estilo. Ang mga istilong tinukoy sa loob ng shadow tree ay naaangkop lamang sa mga elemento sa loob ng puno na iyon. Narito ang isang halimbawa:.

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

Kahit na may magkaibang mga style sa pangunahing dokumento, hindi ito naaapektuhan ang paragraph sa loob ng 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`;
  • Ang paragraph sa loob ng Shadow DOM ay nananatiling berde, habang ang nasa labas ay pula.

Mga kaganapan sa loob ng Shadow DOM

Ang mga kaganapan sa loob ng Shadow DOM ay katulad ng regular na mga kaganapan sa DOM ngunit maaaring kumilos nang naiiba pagdating sa pagpapalaganap dahil sa encapsulation.

Narito ang isang halimbawa:.

 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});
  • Kapag na-click ang button, parehong na-trigger ang mga listener, na nagpapakita ng pag-uugali ng event bubbling.
  • Kapag ang isang event na nagmula sa loob ng Shadow DOM ay umabot pataas sa Light DOM, ang target ng event ay pinapalitan ng host element sa halip na ang orihinal na pinagmulan.
    • Sa halimbawang ito, ang event.target sa loob ng Shadow DOM ay ang totoong button element, ngunit sa labas ng Shadow DOM, ito ay pinapalitan ng host na div element.

Shadow DOM at Custom Elements

Ang Shadow DOM at custom elements ay mga pangunahing bahagi ng Web Components. Ito ay mga teknolohiya na ginagamit para lumikha ng mga reusable at encapsulated na UI components.

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

Ang pangunahing dokumento ay naglalaman ng HTML na ganito:.

1<my-card></my-card>
  • Sa paggamit ng Shadow DOM sa loob ng custom elements, maaari kang gumawa ng reusable components na hindi naaapektuhan ng style conflicts. Sa code na ito, isang tag na tinawag na my-card ang nilikha at iniuugnay sa MyCard na klase. Ang <p> element sa loob ng my-card ay hindi naaapektuhan ng external styles at palaging naka-blue ang pagkaka-display.

Slots: Pamamahagi ng nilalaman mula sa Light DOM

Pinapayagan ka ng slots na maipasa ang nilalaman ng Light DOM papunta sa Shadow DOM. Narito ang isang halimbawa:.

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

Ang pangunahing dokumento ay naglalaman ng HTML na ganito:.

1<my-element>
2    <h3 slot="header">Header Content</h1>
3    <p slot="content">Main Content</p>
4</my-element>
  • Ipinapakita ng slot element sa loob ng Shadow DOM ang nilalaman ng Light DOM na may katugmang slot attribute.

Konklusyon

Ang Shadow DOM ay isang mahalagang kasangkapan sa paggawa ng matibay, maaring magamit muli, at maintainable na mga web component. Sa pamamagitan ng pag-encapsulate ng mga estilo at functionality, nababawasan nito ang posibilidad ng mga tunggalian at pinapasimple ang pamamahala ng codebase.

Maaari mong sundan ang artikulo sa itaas gamit ang Visual Studio Code sa aming YouTube channel. Paki-check din ang aming YouTube channel.

YouTube Video