TypeScript 中的 Shadow DOM

TypeScript 中的 Shadow DOM

本文解釋了 TypeScript 中的 Shadow DOM。

我們將從 Shadow DOM 的基礎到實際應用,仔細說明所有內容,並提供實作範例程式碼。

YouTube Video

typescript-html-shadow-dom.html
  1<!DOCTYPE html>
  2<html lang="en">
  3<head>
  4  <meta charset="UTF-8">
  5  <title>TypeScript &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>
 90
 91    <div class="container">
 92        <h1>JavaScript Console</h1>
 93        <button id="executeBtn">Execute</button>
 94        <div id="output"></div>
 95    </div>
 96
 97    <script>
 98        // Override console.log to display messages in the #output element
 99        (function () {
100            const originalLog = console.log;
101            console.log = function (...args) {
102                originalLog.apply(console, args);
103                const output = document.getElementById('output');
104                output.textContent += args.map(String).join(' ') + '\n';
105            };
106        })();
107
108        document.getElementById('executeBtn').addEventListener('click', () => {
109            // Prevent multiple loads
110            if (document.getElementById('externalScript')) return;
111
112            const script = document.createElement('script');
113            script.src = '/out/main.js';
114            script.id = 'externalScript';
115            //script.onload = () => console.log('typescript-html-shadow-dom.js loaded and executed.');
116            //script.onerror = () => console.log('Failed to load typescript-html-shadow-dom.js.');
117            document.body.appendChild(script);
118        });
119    </script>
120</body>
121</html>

關於 Shadow DOM 的詳細解說和實用逐步指南

Shadow DOM 是 Web Components 的關鍵組成部分之一。它創建了一個封裝的 DOM 樹,將組件的樣式和結構與外部分隔開來。在此,我們將詳細解釋 Shadow DOM 的基礎知識及其實際用例,並提供實踐範例代碼。

Shadow DOM 是什麼?

Shadow DOM 是一種具有以下特性的網頁標準技術。

  1. 封裝

    Shadow DOM 將組件內部的 DOM 結構與外部分離。其他樣式和腳本不會干擾,提高了可重用性。

  2. 獨立的樣式範圍

    Shadow DOM 內的樣式不會影響外部 CSS。同樣,外部樣式不會應用於 Shadow DOM 內部。

  3. 隔離的 DOM 樹

    Shadow DOM 作為與常規 DOM 分離的樹存在,其訪問受到父 DOM 的限制。

Shadow DOM 的基本用法

以下程式碼是使用 Shadow DOM 的第一個範例。

 1class MyElement extends HTMLElement {
 2  constructor() {
 3    super();
 4
 5    // Attach Shadow DOM
 6    const shadowRoot = this.attachShadow({ mode: 'open' });
 7
 8    // Add HTML and CSS inside Shadow DOM
 9    shadowRoot.innerHTML = `
10      <style>
11        p {
12          color: blue;
13          font-size: 18px;
14        }
15      </style>
16      <p>This is inside Shadow DOM!</p>
17    `;
18  }
19}
20
21// Register the custom element
22customElements.define('my-element', MyElement);
23
24document.getElementById('content').innerHTML = `
25  <my-element></my-element>
26`;
  • 瀏覽器將顯示藍色文字:'這是在 Shadow DOM 內部!'。此文字的樣式不受外部 CSS 的影響。

Shadow DOM 的基本步驟

要使用 Shadow DOM,如這個程式碼所示,你需要在 JavaScript 中使用 attachShadow 方法。以下是基本步驟:。

  1. 創建自定義元素 自定義元素是除了標準 HTML 標籤之外,使用者可以創建的自定義標籤。在這個步驟中,你會建立一個繼承自 HTMLElement 的類別,例如 MyElement,讓瀏覽器準備將其識別為新的標籤。通過用 customElements.define() 註冊創建的類別,你就可以在 HTML 中當作自定義標籤來使用它。

  2. 附加 Shadow DOM 在自定義元素內執行 this.attachShadow(),就可以創建 Shadow DOM

  3. Shadow DOM 中添加 HTML 和 CSSShadow DOM 內,你可以自定義 HTML 結構和樣式。例如,將 HTML 和 CSS 設定到 innerHTML,你就能讓它具有獨立於外部 CSS 或 HTML 的外觀和行為。這樣可以讓你創建封裝的元件。

Shadow DOM 的模式:openclosed

Shadow DOM 有兩種模式:openclosed

  • 開放模式:附加到 Shadow DOMshadowRoot 可以從外部存取。
  • 封閉模式:附加到 Shadow DOMshadowRoot 無法從外部存取。

以下是一個程式範例,展示兩種模式之間的差異。

 1class OpenElement extends HTMLElement {
 2  constructor() {
 3    super();
 4    this.attachShadow({ mode: 'open' }).innerHTML = `
 5      <p>Open Shadow DOM</p>
 6    `;
 7  }
 8}
 9
10class ClosedElement extends HTMLElement {
11  constructor() {
12    super();
13    this.attachShadow({ mode: 'closed' }).innerHTML = `
14      <p>Closed Shadow DOM</p>
15    `;
16  }
17}
18
19customElements.define('open-element', OpenElement);
20customElements.define('closed-element', ClosedElement);
21
22document.getElementById('content').innerHTML = `
23  <open-element></open-element>
24  <closed-element></closed-element>
25`;
26
27const openElement = document.querySelector('open-element') as OpenElement;
28console.log(openElement.shadowRoot); // ShadowRootが出力される
29
30const closedElement = document.querySelector('closed-element') as ClosedElement;
31console.log(closedElement.shadowRoot); // nullが出力される
  • 選擇 closed 模式會使 shadowRoot 屬性不可存取。

使用 Shadow DOM 進行樣式封裝

透過使用 Shadow DOM,您可以在元件內完全封裝樣式。

以下範例展示了全域樣式與 Shadow DOM 內部樣式的分離。

 1class StyledElement extends HTMLElement {
 2  constructor() {
 3    super();
 4    const shadowRoot = this.attachShadow({ mode: 'open' });
 5
 6    shadowRoot.innerHTML = `
 7      <style>
 8        p {
 9          background-color: lightblue;
10          padding: 10px;
11          border: 1px solid blue;
12        }
13      </style>
14      <p>Shadow DOM Styled Content</p>
15    `;
16  }
17}
18
19customElements.define('styled-element', StyledElement);
20
21document.getElementById('content').innerHTML = `
22  <style>
23    p {
24      color: red;
25      font-weight: bold;
26    }
27  </style>
28
29  <styled-element></styled-element>
30`;
  • Shadow DOM 內的 p 元素不受全域樣式影響,並具有其獨特的樣式。

Shadow DOM 的實例:自訂工具提示

接下來,我們將介紹如何使用 Shadow DOM 建立自訂工具提示的範例。

 1class Tooltip extends HTMLElement {
 2  constructor() {
 3    super();
 4
 5    const shadowRoot = this.attachShadow({ mode: 'open' });
 6
 7    shadowRoot.innerHTML = `
 8      <style>
 9        :host {
10          position: relative;
11          display: inline-block;
12          cursor: pointer;
13        }
14
15        .tooltip {
16          visibility: hidden;
17          background-color: black;
18          color: white;
19          text-align: center;
20          padding: 5px;
21          border-radius: 5px;
22          position: absolute;
23          bottom: 125%;
24          left: 50%;
25          transform: translateX(-50%);
26          white-space: nowrap;
27        }
28
29        :host(:hover) .tooltip {
30          visibility: visible;
31        }
32      </style>
33      <slot></slot>
34      <div class="tooltip">Tooltip text</div>
35    `;
36  }
37}
38
39customElements.define('custom-tooltip', Tooltip);
40
41document.getElementById('content').innerHTML = `
42  <custom-tooltip>
43    Hover over me
44    <span slot="tooltip">This is a custom tooltip!</span>
45  </custom-tooltip>
46`;
  • 此程式碼會建立一個自訂工具提示,並在懸停時顯示一個帶樣式的工具提示。

總結

Shadow DOM 是 Web Components 的一項關鍵技術,提供了封裝的 DOM 和樣式範圍。在這裡,我們介紹了 Shadow DOM 的基礎、用法、模式差異、樣式封裝,以及實際範例。善用這些特性,你可以構建可重用且健壯的元件。

您可以在我們的 YouTube 頻道上使用 Visual Studio Code 來跟隨上述文章一起學習。 請也查看我們的 YouTube 頻道。

YouTube Video