शैडो रूट, एक एन्कैप्सुलेटेड डीओएम सबट्री है, जो किसी होस्ट एलिमेंट से जुड़ी होती है: इसके अंदर की स्टाइल बाहर नहीं दिखती हैं और पेज की स्टाइल अंदर नहीं दिखती हैं. हालांकि, इनहेरिट की गई प्रॉपर्टी पर यह बात लागू नहीं होती. टेंप्लेट, ट्री को बेहतर तरीके से बनाते हैं; स्लॉट, लाइट DOM कॉन्टेंट को इसमें प्रोजेक्ट करते हैं.
शैडो रूट अटैच करना
this.attachShadow({ mode: 'open', delegatesFocus: true });
delegatesFocus: true, होस्ट पर फ़ोकस करने पर, फ़ोकस को शैडो ट्री के अंदर मौजूद पहले फ़ोकस किए जा सकने वाले एलिमेंट पर ले जाता है. साथ ही, :focus स्टाइल को होस्ट पर रूट करता है. इसके अलावा, फ़ॉर्म से जुड़े कस्टम एलिमेंट (static formAssociated = true) पर, <label> क्लिक को अंदरूनी कंट्रोल पर फ़ॉरवर्ड करता है. इसे तब सेट करें, जब कॉम्पोनेंट में फ़ोकस किए जा सकने वाले कंट्रोल शामिल हों. ज़्यादातर मामलों में mode: 'open' का इस्तेमाल करें, ताकि डेवलपर टूल, पेज स्क्रिप्ट, और सर्वर हाइड्रेशन element.shadowRoot तक पहुंच सकें. इस बारे में ज़्यादा जानने के लिए, वेब कॉम्पोनेंट ओरिएंटेशन देखें.
टेंप्लेट: ट्री को बेहतर तरीके से बनाएं
<template> को एक बार (मॉड्यूल स्कोप या स्टैटिक फ़ील्ड) तय करें और हर इंस्टेंस के लिए इसे क्लोन करें. पार्स किए गए फ़्रैगमेंट को क्लोन करना, हर बार innerHTML स्ट्रिंग को फिर से पार्स करने की तुलना में काफ़ी तेज़ होता है.
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);
टेंप्लेट को आसान रखें. डीपली नेस्टेड "div soup" और नेस्टेड शैडो रूट के कई लेवल, दोनों ही स्टाइल-रिज़ॉल्यूशन और लेआउट की लागत को बढ़ाते हैं. इससे बड़े पैमाने पर परफ़ॉर्मेंस पर असर पड़ता है. फ़्लैट स्ट्रक्चर और सिमैंटिक एलिमेंट को प्राथमिकता दें.
स्लॉट: वे हिस्से जो लोगों को हैरान करते हैं
डिफ़ॉल्ट और नाम वाले स्लॉट, दस्तावेज़ के मुताबिक काम करते हैं. हालांकि, ये व्यवहार परेशानी का सबब बन सकते हैं:
- खाली सफ़ेद जगह (व्हाइटस्पेस) की संख्या. एलिमेंट के बीच के टेक्स्ट नोड (इनमें खाली सफ़ेद जगह भी शामिल है) को डिफ़ॉल्ट स्लॉट में असाइन किया जाता है. इसलिए, डिफ़ॉल्ट स्लॉट शायद ही कभी "खाली" होता है.
- डीओएम का क्रम सुरक्षित रहता है, स्लॉट का क्रम नहीं. प्रोजेक्ट किए गए नोड,
:first-child/:last-childके लिए अपने ओरिजनल लाइट डीओएम ऑर्डर को बनाए रखते हैं. भले ही, वे किसी भी स्लॉट को भरें.::slotted(*:first-child)नियम, पहले DOM चाइल्ड को टारगेट करता है, न कि उस स्लॉट के पहले चाइल्ड को. इसलिए, यह अक्सर आपकी उम्मीद के मुताबिक मैच नहीं होता. slotchange, अपग्रेड करने के समय का सिग्नल है. यह तब ट्रिगर होता है, जब असाइन किए गए नोड में बदलाव होता है. इसमें शुरुआती असाइनमेंट भी शामिल है. यह अपग्रेड के बाद, लाइट डीओएम चाइल्ड के आने की जानकारी पाने का भरोसेमंद तरीका है. ऐसा तब होता है, जब वेconnectedCallbackके दौरान मौजूद न हों.
this.shadowRoot.querySelector('slot[name="header"]')
.addEventListener('slotchange', (e) => {
const nodes = e.target.assignedElements();
this.toggleAttribute('has-header', nodes.length > 0);
});
शैडो रूट में स्टाइलशीट लोड करना
| तरीका | फ़ायदे | नुकसान |
|---|---|---|
टेंप्लेट में <style> |
यह आसान है, पूरी तरह से एन्कैप्सुलेटेड है, और JS के बिना काम करता है. | हर इंस्टेंस के लिए डुप्लीकेट किया जाता है. इससे डीओएम का साइज़ बड़े पैमाने पर बढ़ता है. |
<link rel="stylesheet"> |
कैश मेमोरी में सेव की जा सकने वाली बाहरी फ़ाइल. | अतिरिक्त अनुरोध; बिना स्टाइल वाले कॉन्टेंट के फ़्लैश होने का खतरा. |
adoptedStyleSheets |
सभी इंस्टेंस के लिए एक शेयर किया गया CSSStyleSheet; बड़े पैमाने पर सबसे तेज़. |
इसके लिए JS ज़रूरी है; बनाई गई शीट में @import का इस्तेमाल नहीं किया जा सकता. |
किसी कॉम्पोनेंट के कई इंस्टेंस के लिए, शेयर की गई कंस्ट्रक्टेड स्टाइलशीट को प्राथमिकता दें:
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];
}
}