Shadow DOM ใน TypeScript

Shadow DOM ใน TypeScript

บทความนี้อธิบายเกี่ยวกับ Shadow DOM ใน TypeScript

เราจะอธิบายทุกอย่างอย่างละเอียดตั้งแต่พื้นฐานของ 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 tree ที่ถูกแยกออกมาโดยเฉพาะ ซึ่งช่วยแยกสไตล์และโครงสร้างของส่วนประกอบออกจากภายนอก ที่นี่ เราจะให้คำอธิบายเชิงลึกตั้งแต่พื้นฐานของ Shadow DOM ไปจนถึงวิธีใช้งานในเชิงปฏิบัติ พร้อมตัวอย่างโค้ดให้ทดลองมือ

Shadow DOM คืออะไร?

Shadow DOM เป็นเทคโนโลยีมาตรฐานเว็บที่มีคุณสมบัติดังต่อไปนี้

  1. การห่อหุ้ม (Encapsulation)

    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 ตามตัวอย่างโค้ดนี้ คุณจะใช้เมธอด attachShadow ในภาษา JavaScript ขั้นตอนพื้นฐานมีดังต่อไปนี้:

  1. การสร้าง Custom Elements คัสตอมอีเลเมนต์คือแท็กที่คุณกำหนดเองได้เพิ่มเติมจากแท็ก HTML มาตรฐาน ในขั้นตอนนี้ คุณจะสร้างคลาสที่ขยายจาก HTMLElement เช่นคลาส MyElement เพื่อให้เบราว์เซอร์รู้จักเป็นแท็กใหม่ โดยการลงทะเบียนคลาสที่สร้างไว้ด้วย customElements.define() คุณจะสามารถใช้เป็นแท็กแบบคัสตอมใน HTML ได้

  2. การผูก Shadow DOM ด้วยการเรียก this.attachShadow() ภายในคัสตอมอีเลเมนต์ คุณจะสามารถสร้าง Shadow DOM ได้

  3. การเพิ่ม HTML และ CSS ภายใน Shadow DOM ภายใน Shadow DOM คุณสามารถกำหนดโครงสร้าง HTML และรูปแบบสไตล์ของตนเองได้ ตัวอย่างเช่น การกำหนด HTML และ CSS ลงใน innerHTML จะทำให้มีรูปร่างและพฤติกรรมที่เป็นอิสระ ไม่ถูกรบกวนโดย CSS หรือ HTML จากภายนอก ซึ่งจะช่วยให้คุณสร้างคอมโพเนนต์ที่เป็นเอกเทศ

โหมดของ Shadow DOM: open และ closed

Shadow DOM มีสองโหมด: open และ closed

  • โหมด Open: สามารถเข้าถึง shadowRoot ที่แนบอยู่กับ Shadow DOM จากภายนอกได้
  • โหมด Closed: ไม่สามารถเข้าถึง shadowRoot ที่แนบอยู่กับ Shadow DOM จากภายนอกได้

ด้านล่างเป็นโค้ดตัวอย่างที่แสดงความแตกต่างระหว่างสองโหมด

 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`;
  • องค์ประกอบ p ที่อยู่ภายใน Shadow DOM จะไม่ได้รับผลกระทบจากสไตล์แบบทั่วโลก และจะมีสไตล์เฉพาะตัวของตนเองถูกนำมาใช้

ตัวอย่างการใช้งาน 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 การใช้งาน ความแตกต่างของโหมด การห่อหุ้มสไตล์ และตัวอย่างการใช้งานจริง ด้วยการใช้ประโยชน์จากคุณสมบัติเหล่านี้ คุณจะสามารถสร้างคอมโพเนนต์ที่นำกลับมาใช้ได้และแข็งแกร่ง

คุณสามารถติดตามบทความข้างต้นโดยใช้ Visual Studio Code บนช่อง YouTube ของเรา กรุณาตรวจสอบช่อง YouTube ด้วย

YouTube Video