Shadow DOM inkapsulyatsiya uchun xizmat qiladi. U komponentga o’zining “soya” DOM daraxtiga ega bo’lish imkonini beradi, unga asosiy hujjatdan tasodifan kirish mumkin emas, mahalliy uslub qoidalari bo’lishi mumkin va boshqalar.
O’rnatilgan shadow DOM
Siz hech qachon murakkab brauzer boshqaruv elementlari qanday yaratilishi va shakllantirilanishi haqida o’ylab ko’rganmisiz?
Masalan <input type="range">:
Brauzer ularni chizish uchun ichkarida DOM/CSS dan foydalanadi. Bu DOM tuzilmasi odatda bizdan yashiringan, lekin biz uni dasturchi vositalarida ko’rishimiz mumkin. Masalan, Chrome da biz Dev Tools da “Show user agent shadow DOM” opsiyasini yoqishimiz kerak.
Keyin <input type="range"> quyidagicha ko’rinadi:
#shadow-root ostida ko’rayotgan narsa “shadow DOM” deb ataladi.
Biz o’rnatilgan shadow DOM elementlarini oddiy JavaScript chaqiruvlari yoki selektorlar orqali ola olmaymiz. Bular oddiy bolalar emas, balki kuchli inkapsulyatsiya texnikasi.
Yuqoridagi misolda biz foydali pseudo atributini ko’rishimiz mumkin. Bu nostandart, tarixiy sabablarga ko’ra mavjud. Biz uni CSS bilan subelementlarni shakllantirish uchun ishlatishimiz mumkin:
<style>
/* slayder yo'lini qizil qiling */
input::-webkit-slider-runnable-track {
background: red;
}
</style>
<input type="range">
Yana bir bor, pseudo nostandart atribut. Xronologik jihatdan, brauzerlar avval boshqaruv elementlarini amalga oshirish uchun ichki DOM tuzilmalari bilan tajriba qila boshladilar va keyin vaqt o’tgach, shadow DOM standartlashtirildi, bizga, dasturchilarga xuddi shunday ishni qilish imkonini berish uchun.
Bundan keyin biz DOM spec va boshqa tegishli spetsifikatsiyalar tomonidan qamrab olingan zamonaviy shadow DOM standartidan foydalanamiz.
Shadow darakti
DOM elementi ikkita turdagi DOM subdaraxtlariga ega bo’lishi mumkin:
- Light tree – HTML bolalardan tuzilgan oddiy DOM subdaxti. Oldingi boblarda ko’rgan barcha subdaxtlar “light” edi.
- Shadow tree – yashirin DOM subdaxti, HTML da aks etmaydi, ko’zlardan yashiringan.
Agar elementda ikkalasi ham bo’lsa, brauzer faqat shadow daraxtini render qiladi. Lekin biz shadow va light daxtlar o’rtasida qandaydir kompozitsiya ham o’rnatishimiz mumkin. Tafsilotlarni keyinroq Shadow DOM slotlar, kompozitsiya bobida ko’ramiz.
Shadow tree Custom Elements da komponent ichki qismlarini yashirish va komponent-mahalliy uslublarni qo’llash uchun ishlatilishi mumkin.
Masalan, bu <show-hello> elementi o’zining ichki DOM ini shadow tree da yashiradi:
<script>
customElements.define('show-hello', class extends HTMLElement {
connectedCallback() {
const shadow = this.attachShadow({mode: 'open'});
shadow.innerHTML = `<p>
Salom, ${this.getAttribute('name')}
</p>`;
}
});
</script>
<show-hello name="John"></show-hello>
Chrome dev tools da natijada paydo bo’lgan DOM quyidagicha ko’rinadi, barcha kontent “#shadow-root” ostida:
Birinchi, elem.attachShadow({mode: …}) ga chaqiruv shadow daraxtini yaratadi.
Ikkita cheklov bor:
- Biz har bir element uchun faqat bitta shadow root yaratishimiz mumkin.
elemcustom element yoki quyidagilardan biri bo’lishi kerak: “article”, “aside”, “blockquote”, “body”, “div”, “footer”, “h1…h6”, “header”, “main” “nav”, “p”, “section”, yoki “span”. Boshqa elementlar, masalan<img>, shadow tree ni joylashtirib bo’lmaydi.
mode opsiyasi inkapsulyatsiya darajasini belgilaydi. U ikkita qiymatdan birini olishi kerak:
-
"open"– shadow rootelem.shadowRootsifatida mavjud.Har qanday kod
elemning shadow tree ga kirishga qodir. -
"closed"–elem.shadowRoothar doimnull.Biz shadow DOM ga faqat
attachShadowtomonidan qaytarilgan havola orqali kirishimiz mumkin (va ehtimol klass ichida yashiringan). Brauzer-mahalliy shadow daxtlari, masalan<input type="range">, yopiq. Ularga kirish yo’li yo’q.
attachShadow tomonidan qaytarilgan shadow root element kabi: biz uni to’ldirish uchun innerHTML yoki append kabi DOM metodlaridan foydalanishimiz mumkin.
Shadow root ga ega element “shadow tree host” deb ataladi va shadow root host xususiyati sifatida mavjud:
// {mode: "open"} deb faraz qilsak, aks holda elem.shadowRoot null
alert(elem.shadowRoot.host === elem); // true
Inkapsulyatsiya
Shadow DOM asosiy hujjatdan qattiq ajratilgan:
- Shadow DOM elementlari light DOM dan
querySelectoruchun ko’rinmaydi. Xususan, Shadow DOM elementlarida light DOM dagi bilan to’qnashadigan id lar bo’lishi mumkin. Ular faqat shadow tree ichida noyob bo’lishi kerak. - Shadow DOM o’z stylesheetlariga ega. Tashqi DOM dan uslub qoidalari qo’llanilmaydi.
Masalan:
<style>
/* hujjat uslubi #elem ichidagi shadow tree ga qo'llanilmaydi (1) */
p { color: red; }
</style>
<div id="elem"></div>
<script>
elem.attachShadow({mode: 'open'});
// shadow tree o'z uslubiga ega (2)
elem.shadowRoot.innerHTML = `
<style> p { font-weight: bold; } </style>
<p>Salom, John!</p>
`;
// <p> faqat shadow tree ichidagi so'rovlardan ko'rinadi (3)
alert(document.querySelectorAll('p').length); // 0
alert(elem.shadowRoot.querySelectorAll('p').length); // 1
</script>
- Hujjatdagi uslub shadow tree ga ta’sir qilmaydi.
- …Lekin ichkaridagi uslub ishlaydi.
- Shadow tree dagi elementlarni olish uchun biz daraxt ichidan so’rov qilishimiz kerak.
Manbalar
- DOM: https://dom.spec.whatwg.org/#shadow-trees
- Muvofiqlik: https://caniuse.com/#feat=shadowdomv1
- Shadow DOM ko’plab boshqa spetsifikatsiyalarda ham eslatib o’tiladi, masalan DOM Parsing shadow root
innerHTMLga ega ekanligini belgilaydi.
Xulosa
Shadow DOM komponent-mahalliy DOM yaratish usuli.
shadowRoot = elem.attachShadow({mode: open|closed})–elemuchun shadow DOM yaratadi. Agarmode="open"bo’lsa, uelem.shadowRootxususiyati sifatida mavjud.- Biz
shadowRootniinnerHTMLyoki boshqa DOM metodlar yordamida to’ldirishimiz mumkin.
Shadow DOM elementlari:
- O’z id makoniga ega,
- Asosiy hujjatdan JavaScript selektorlari, masalan
querySelectoruchun ko’rinmaydi, - Asosiy hujjatdan emas, faqat shadow tree dan uslublarni ishlatadi.
Shadow DOM, agar mavjud bo’lsa, “light DOM” (oddiy bolalar) deb ataladigan narsaning o’rniga brauzer tomonidan render qilinadi. Shadow DOM slotlar, kompozitsiya bobida biz ularni qanday birlashtirish mumkinligini ko’ramiz.
Izohlar
<code>yorlig'ini ishlating, bir nechta satrlar uchun - ularni<pre>yorlig'i bilan o'rab qo'ying, 10 satrdan ortiq bo'lsa - sandbox (plnkr, jsbin, codepen…)