Shadow root adalah subhierarki DOM yang dienkapsulasi dan dilampirkan ke elemen host: gaya di dalamnya tidak bocor, dan gaya halaman tidak bocor (kecuali properti yang diwariskan). Template membuat hierarki secara efisien; slot memproyeksikan konten Light DOM ke dalamnya.
Menambahkan shadow root
this.attachShadow({ mode: 'open', delegatesFocus: true });
delegatesFocus: true membuat pemfokusan host memindahkan fokus ke elemen pertama yang dapat difokuskan di dalam shadow tree, merutekan gaya visual :focus ke host, dan pada elemen kustom yang terkait dengan formulir (static formAssociated = true) meneruskan klik <label> ke kontrol dalam. Tetapkan setiap kali komponen menggabungkan kontrol yang dapat difokuskan. Gunakan mode: 'open' di hampir semua kasus agar alat developer, skrip halaman, dan hidrasi server dapat menjangkau element.shadowRoot (lihat Orientasi Komponen Web).
Template: membuat hierarki secara efisien
Tentukan <template> sekali (cakupan modul atau kolom statis) dan clone per instance. Meng-clone fragmen yang diurai jauh lebih cepat daripada mengurai ulang string innerHTML pada setiap konstruksi.
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);
Buat template tetap ringkas. "Sup div" yang sangat bertingkat dan banyak tingkat root bayangan bertingkat menambah biaya resolusi gaya dan tata letak yang terukur, yang merupakan penurunan performa yang signifikan dalam skala besar. Pilih struktur datar dan elemen semantik.
Slot: bagian yang mengejutkan orang
Slot default vs. slot bernama berfungsi seperti yang didokumentasikan; berikut adalah perilaku yang mengganggu:
- Spasi kosong dihitung. Node teks di antara elemen (termasuk spasi kosong murni) ditetapkan ke slot default, sehingga slot default jarang benar-benar "kosong".
- Urutan DOM dipertahankan, bukan urutan slot. Node yang diproyeksikan mempertahankan urutan Light DOM aslinya untuk tujuan
:first-child/:last-child, terlepas dari slot yang diisinya. Aturan::slotted(*:first-child)menargetkan turunan DOM pertama, bukan turunan pertama slot tersebut, sehingga sering kali tidak cocok dengan yang Anda harapkan. slotchangeadalah sinyal waktu upgrade. Peristiwa ini diaktifkan saat node yang ditetapkan berubah (termasuk penetapan awal) dan merupakan cara yang andal untuk mengetahui bahwa turunan Light DOM telah tiba setelah upgrade, saat turunan tersebut mungkin belum ada selamaconnectedCallback.
this.shadowRoot.querySelector('slot[name="header"]')
.addEventListener('slotchange', (e) => {
const nodes = e.target.assignedElements();
this.toggleAttribute('has-header', nodes.length > 0);
});
Memuat stylesheet ke dalam shadow root
| Metode | Kelebihan | Kekurangan |
|---|---|---|
<style> di template |
Sederhana, dienkapsulasi sepenuhnya, berfungsi tanpa JS. | Diduplikasi per instance; memperbesar DOM dalam skala besar. |
<link rel="stylesheet"> |
File eksternal yang dapat di-cache. | Permintaan tambahan; berisiko menampilkan konten tanpa gaya. |
adoptedStyleSheets |
Satu CSSStyleSheet bersama di semua instance; tercepat dalam skala besar. |
Memerlukan JS; sheet yang dibuat tidak mendukung @import. |
Untuk banyak instance dari satu komponen, sebaiknya gunakan stylesheet yang dibuat bersama:
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];
}
}