Shadow DOM trong TypeScript
Bài viết này giải thích về Shadow DOM trong TypeScript.
Chúng tôi sẽ giải thích cẩn thận mọi thứ từ kiến thức cơ bản về Shadow DOM
đến cách sử dụng thực tế, đồng thời cung cấp mã mẫu thực hành.
YouTube Video
typescript-html-shadow-dom.html
1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="UTF-8">
5 <title>TypeScript & 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>
Giải thích chi tiết và hướng dẫn từng bước thực tiễn về Shadow DOM
Shadow DOM
là một trong những thành phần chính của Web Components. Nó tạo ra một cây DOM được đóng gói, tách biệt kiểu dáng và cấu trúc của thành phần khỏi bên ngoài. Ở đây, chúng tôi sẽ cung cấp một giải thích chi tiết từ các khái niệm cơ bản của Shadow DOM
đến các trường hợp sử dụng thực tiễn, kèm theo mã mẫu thực hành.
Shadow DOM
là gì?
Shadow DOM
là một công nghệ chuẩn web với các đặc điểm sau.
-
Đóng gói
Shadow DOM
tách biệt cấu trúc DOM nội bộ của một thành phần khỏi bên ngoài. Các kiểu dáng và script khác không can thiệp, nâng cao khả năng tái sử dụng. -
Phạm vi kiểu dáng độc lập
Các kiểu dáng bên trong
Shadow DOM
không ảnh hưởng đến CSS bên ngoài. Tương tự, các kiểu dáng bên ngoài không áp dụng bên trongShadow DOM
. -
Cây DOM độc lập
Shadow DOM
tồn tại như một cây tách biệt khỏi DOM thông thường, với quyền truy cập bị giới hạn từ DOM cha.
Cách sử dụng cơ bản của Shadow DOM
Đoạn mã sau là ví dụ đầu tiên sử dụng 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`;
- Trình duyệt sẽ hiển thị văn bản màu xanh: 'Đây là bên trong Shadow DOM!'. Kiểu của văn bản này không bị ảnh hưởng bởi CSS bên ngoài.
Các bước cơ bản của Shadow DOM
Để sử dụng Shadow DOM
, như minh họa trong đoạn mã này, bạn sử dụng phương thức attachShadow
trong JavaScript. Dưới đây là các bước cơ bản:.
-
Tạo các phần tử tùy chỉnh Phần tử tùy chỉnh là thẻ do người dùng định nghĩa mà bạn có thể tạo thêm bên cạnh các thẻ HTML tiêu chuẩn. Ở bước này, bạn tạo một lớp kế thừa từ
HTMLElement
, ví dụ như lớpMyElement
, để trình duyệt có thể nhận diện nó như một thẻ mới. Bằng cách đăng ký lớp vừa tạo vớicustomElements.define()
, bạn có thể sử dụng nó như một thẻ tùy chỉnh trong HTML. -
Gắn thêm
Shadow DOM
Bằng cách thực thithis.attachShadow()
bên trong một phần tử tùy chỉnh, bạn có thể tạo mộtShadow DOM
. -
Thêm HTML và CSS vào bên trong
Shadow DOM
Bên trongShadow DOM
, bạn có thể định nghĩa cấu trúc HTML và các kiểu CSS của riêng mình. Ví dụ, bằng cách gán HTML và CSS vàoinnerHTML
, bạn có thể tạo giao diện và hành vi độc lập mà không bị ảnh hưởng bởi CSS hoặc HTML bên ngoài. Điều này cho phép bạn tạo ra các thành phần được đóng gói.
Chế độ của Shadow DOM
: mở
và đóng
Shadow DOM
có hai chế độ: mở
và đóng
.
- Chế độ mở:
shadowRoot
gắn vớiShadow DOM
có thể được truy cập từ bên ngoài. - Chế độ đóng:
shadowRoot
gắn vớiShadow DOM
không thể được truy cập từ bên ngoài.
Dưới đây là một ví dụ mã cho thấy sự khác biệt giữa hai chế độ.
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が出力される
- Chọn chế độ
đóng
sẽ làm thuộc tínhshadowRoot
không thể truy cập.
Bao bọc kiểu dáng bằng cách sử dụng Shadow DOM
Bằng cách sử dụng Shadow DOM
, bạn có thể hoàn toàn đóng gói kiểu dáng bên trong các thành phần của mình.
Ví dụ sau minh họa sự tách biệt giữa các kiểu dáng toàn cầu và các kiểu dáng trong 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
bên trongShadow DOM
không bị ảnh hưởng bởi các kiểu dáng toàn cục và có các kiểu dáng riêng biệt của chúng được áp dụng`.
Ví dụ thực tế của Shadow DOM
: Tooltip tùy chỉnh
Tiếp theo, chúng tôi giới thiệu một ví dụ về việc tạo tooltip tùy chỉnh bằng 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`;
- Đoạn mã này tạo một tooltip tùy chỉnh và hiển thị tooltip có kiểu dáng khi di chuột.
Tóm tắt
Shadow DOM
là một công nghệ quan trọng đối với Web Components, cung cấp một DOM và phạm vi kiểu dáng được bao bọc. Ở đây, chúng tôi đã đề cập đến những điều cơ bản về Shadow DOM
, cách sử dụng, sự khác biệt trong chế độ, bao gói kiểu dáng, và các ví dụ thực tế. Bằng cách tận dụng những điều này, bạn có thể xây dựng các thành phần có thể tái sử dụng và mạnh mẽ.
Bạn có thể làm theo bài viết trên bằng cách sử dụng Visual Studio Code trên kênh YouTube của chúng tôi. Vui lòng ghé thăm kênh YouTube.