Gốc tối là một cây con DOM được đóng gói và đính kèm vào một phần tử lưu trữ: các kiểu bên trong không bị rò rỉ ra ngoài và các kiểu trang không bị rò rỉ vào trong (ngoại trừ các thuộc tính kế thừa). Mẫu tạo cây một cách hiệu quả; khe chiếu nội dung DOM sáng vào cây.
Đính kèm gốc bóng
this.attachShadow({ mode: 'open', delegatesFocus: true });
delegatesFocus: true giúp việc lấy tiêu điểm vào máy chủ lưu trữ di chuyển tiêu điểm đến phần tử có thể lấy tiêu điểm đầu tiên bên trong cây bóng, định tuyến kiểu :focus đến máy chủ lưu trữ và trên các phần tử tuỳ chỉnh liên kết với biểu mẫu (static formAssociated = true) chuyển tiếp lượt nhấp <label> đến thành phần điều khiển bên trong. Hãy đặt thuộc tính này bất cứ khi nào thành phần gói các thành phần điều khiển có thể làm tâm điểm. Sử dụng mode: 'open' trong hầu hết các trường hợp để các công cụ cho nhà phát triển, tập lệnh trang và quá trình hydrat hoá máy chủ có thể tiếp cận element.shadowRoot (xem Hướng dẫn về thành phần web).
Mẫu: xây dựng cây một cách hiệu quả
Xác định <template> một lần (phạm vi mô-đun hoặc trường tĩnh) và sao chép cho mỗi thực thể. Việc sao chép một mảnh đã phân tích cú pháp sẽ nhanh hơn nhiều so với việc phân tích cú pháp lại một chuỗi innerHTML trên mỗi cấu trúc.
const template = document.createElement('template');
template.innerHTML = `
<div class="card">
<slot name="header"></slot>
<div class="body"><slot></slot></div>
<slot name="footer"></slot>
</div>
`;
class MyCard extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
// MANDATORY: deep-clone the template content so each instance gets its own nodes.
this.shadowRoot.append(template.content.cloneNode(true));
}
}
customElements.define('my-card', MyCard);
Giữ cho mẫu gọn gàng. "Div soup" lồng sâu và nhiều cấp độ gốc bóng lồng nhau đều làm tăng chi phí bố cục và độ phân giải kiểu có thể đo lường, một ảnh hưởng lớn đến hiệu suất trên quy mô lớn. Ưu tiên cấu trúc phẳng và các phần tử ngữ nghĩa.
Vị trí: những phần khiến mọi người bất ngờ
Vị trí mặc định so với vị trí được đặt tên hoạt động như được ghi lại; đây là những hành vi gây khó khăn:
- Khoảng trắng cũng được tính. Các nút văn bản giữa các phần tử (bao gồm cả khoảng trắng thuần tuý) được chỉ định cho vùng quảng cáo mặc định, vì vậy, vùng quảng cáo mặc định hiếm khi thực sự "trống".
- Thứ tự DOM được giữ nguyên, không phải thứ tự vị trí. Các nút được chiếu giữ nguyên thứ tự DOM sáng ban đầu cho mục đích
:first-child/:last-child, bất kể chúng lấp đầy vị trí nào. Quy tắc::slotted(*:first-child)nhắm đến phần tử con DOM đầu tiên, chứ không phải phần tử con đầu tiên của vùng đó, vì vậy, quy tắc này thường không khớp với những gì bạn mong đợi. slotchangelà tín hiệu về thời điểm nâng cấp. Sự kiện này kích hoạt khi các nút được chỉ định thay đổi (bao gồm cả chỉ định ban đầu) và là cách đáng tin cậy để biết các phần tử con của Light DOM đã xuất hiện sau khi nâng cấp, khi chúng có thể chưa tồn tại trongconnectedCallback.
this.shadowRoot.querySelector('slot[name="header"]')
.addEventListener('slotchange', (e) => {
const nodes = e.target.assignedElements();
this.toggleAttribute('has-header', nodes.length > 0);
});
Tải biểu định kiểu vào gốc bóng
| Phương thức | Ưu điểm | Nhược điểm |
|---|---|---|
<style> trong mẫu |
Đơn giản, được đóng gói đầy đủ, hoạt động mà không cần JS. | Bị trùng lặp trên mỗi thực thể; làm tăng kích thước DOM trên quy mô lớn. |
<link rel="stylesheet"> |
Tệp bên ngoài có thể lưu vào bộ nhớ đệm. | Yêu cầu bổ sung; có nguy cơ xuất hiện nội dung chưa được tạo kiểu. |
adoptedStyleSheets |
Một CSSStyleSheet dùng chung trên tất cả các thực thể; nhanh nhất khi mở rộng quy mô. |
Yêu cầu JS; trang tính được tạo không hỗ trợ @import. |
Đối với nhiều thực thể của một thành phần, hãy ưu tiên biểu định kiểu được tạo chung:
const sheet = new CSSStyleSheet();
sheet.replaceSync(`:host { display: block; }`);
class MyCard extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
// The same sheet object is reused by every instance; no per-instance parse.
this.shadowRoot.adoptedStyleSheets = [sheet];
}
}