Теневой DOM («Shadow DOM») иÑполÑзÑеÑÑÑ Ð´Ð»Ñ Ð¸Ð½ÐºÐ°Ð¿ÑÑлÑÑии. ÐлагодаÑÑ ÐµÐ¼Ñ Ð² компоненÑе еÑÑÑ ÑобÑÑвенное «Ñеневое» DOM-деÑево, к коÑоÑÐ¾Ð¼Ñ Ð½ÐµÐ»ÑÐ·Ñ Ð¿ÑоÑÑо Ñак обÑаÑиÑÑÑÑ Ð¸Ð· главного докÑменÑа, Ñ Ð½ÐµÐ³Ð¾ могÑÑ Ð±ÑÑÑ Ð¸Ð·Ð¾Ð»Ð¸ÑованнÑе CSS-пÑавила и Ñ.д.
ÐÑÑÑоеннÑй Ñеневой DOM
ÐадÑмÑвалиÑÑ Ð»Ð¸ Ð²Ñ Ð¾ Ñом, как ÑÑÑÑÐ¾ÐµÐ½Ñ Ð¸ ÑÑÐ¸Ð»Ð¸Ð·Ð¾Ð²Ð°Ð½Ñ ÑложнÑе бÑаÑзеÑнÑе ÑлеменÑÑ ÑпÑавлениÑ?
ÐапÑимеÑ, <input type="range">:
ÐÑаÑÐ·ÐµÑ ÑиÑÑÐµÑ Ð¸Ñ Ñвоими Ñилами и по ÑÐ²Ð¾ÐµÐ¼Ñ ÑÑмоÑÑениÑ. ÐÑ DOM-ÑÑÑÑкÑÑÑа обÑÑно нам не видна, но в инÑÑÑÑменÑÐ°Ñ ÑазÑабоÑÑика можно ÐµÑ Ð¿Ð¾ÑмоÑÑеÑÑ. РпÑимеÑÑ, в Chrome Ð´Ð»Ñ ÑÑого нÑжно акÑивиÑоваÑÑ Ð¿ÑÐ½ÐºÑ Â«Show user agent shadow DOM».
ÐоÑле ÑÑого <input type="range"> вÑглÑÐ´Ð¸Ñ Ñак:
То, ÑÑо наÑ
одиÑÑÑ Ð¿Ð¾Ð´ #shadow-root â и назÑваеÑÑÑ Â«shadow DOM» (Ñеневой DOM).
ÐÑ Ð½Ðµ можем полÑÑиÑÑ Ð´Ð¾ÑÑÑп к ÑÐµÐ½ÐµÐ²Ð¾Ð¼Ñ DOM вÑÑÑоеннÑÑ ÑлеменÑов Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ Ð¾Ð±ÑÑнÑÑ JavaScript-вÑзовов или Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ ÑелекÑоÑов. ÐÑо не пÑоÑÑо обÑÑнÑе поÑомки, ÑÑо моÑное ÑÑедÑÑво инкапÑÑлÑÑии.
РпÑимеÑе вÑÑе можно ÑвидеÑÑ Ð¿Ð¾Ð»ÐµÐ·Ð½Ñй аÑÑибÑÑ pseudo. Ðн неÑÑандаÑÑнÑй и ÑÑÑеÑÑвÑÐµÑ Ð¿Ð¾ иÑÑоÑиÑеÑким пÑиÑинам. С его помоÑÑÑ Ð¼Ð¾Ð¶Ð½Ð¾ ÑÑилизоваÑÑ Ð¿Ð¾Ð´ÑлеменÑÑ ÑеÑез CSS, напÑимеÑ, Ñак:
<style>
/* делаем ÑÐ²ÐµÑ ÑÐºÐ°Ð»Ñ Ð¿Ð¾Ð»Ð·Ñнка кÑаÑнÑм */
input::-webkit-slider-runnable-track {
background: red;
}
</style>
<input type="range">
ÐÑÑ Ñаз замеÑим, ÑÑо pseudo â неÑÑандаÑÑнÑй аÑÑибÑÑ. ÐÑли говоÑиÑÑ Ñ
ÑонологиÑеÑки, Ñо ÑнаÑала бÑаÑзеÑÑ Ð½Ð°Ñали ÑкÑпеÑименÑиÑоваÑÑ Ñ Ð¸Ð½ÐºÐ°Ð¿ÑÑлÑÑией внÑÑÑенниÑ
DOM-ÑÑÑÑкÑÑÑ Ð´Ð»Ñ ÑлеменÑов, а Ñже поÑом, ÑеÑез некоÑоÑое вÑемÑ, поÑвилÑÑ ÑÑандаÑÑ Shadow DOM, коÑоÑÑй позволÑÐµÑ Ð´ÐµÐ»Ð°ÑÑ Ñо же Ñамое нам, ÑазÑабоÑÑикам.
Ðалее Ð¼Ñ Ð²Ð¾ÑполÑзÑемÑÑ ÑовÑеменнÑм ÑÑандаÑÑом Shadow DOM, опиÑаннÑм в ÑпеÑиÑикаÑии DOM spec и дÑÑÐ³Ð¸Ñ ÑпеÑиÑикаÑиÑÑ .
Теневое деÑево
ÐаждÑй DOM-ÑÐ»ÐµÐ¼ÐµÐ½Ñ Ð¼Ð¾Ð¶ÐµÑ Ð¸Ð¼ÐµÑÑ 2 Ñипа поддеÑевÑев DOM:
- Light tree â обÑÑное, «ÑвеÑлое», DOM-поддеÑево, ÑоÑÑоÑÑее из HTML-поÑомков. ÐÑе поддеÑевÑÑ, о коÑоÑÑÑ Ð¼Ñ Ð³Ð¾Ð²Ð¾Ñили в пÑедÑдÑÑÐ¸Ñ Ð³Ð»Ð°Ð²Ð°Ñ , бÑли «light».
- Shadow tree â ÑкÑÑÑое, «Ñеневое», DOM-поддеÑево, не оÑÑажÑнное в HTML, ÑкÑÑÑое Ð¾Ñ Ð¿Ð¾ÑÑоÑÐ¾Ð½Ð½Ð¸Ñ Ð³Ð»Ð°Ð·.
ÐÑли Ñ ÑлеменÑа имеÑÑÑÑ Ð¾Ð±Ð° поддеÑева, бÑаÑÐ·ÐµÑ Ð¾ÑÑиÑовÑÐ²Ð°ÐµÑ ÑолÑко Ñеневое деÑево. Также Ð¼Ñ Ð²ÑÑ Ð¶Ðµ можем задаÑÑ Â«ÐºÐ¾Ð¼Ð¿Ð¾Ð·Ð¸ÑиÑ» Ñеневого и обÑÑного деÑевÑев. Ðозже в главе СлоÑÑ Ñеневого DOM, композиÑÐ¸Ñ Ð¼Ñ ÑаÑÑмоÑÑим деÑали.
Теневое деÑево можно иÑполÑзоваÑÑ Ð² полÑзоваÑелÑÑÐºÐ¸Ñ ÑлеменÑÐ°Ñ (Custom Elements), ÑÑÐ¾Ð±Ñ ÑпÑÑÑаÑÑ Ð²Ð½ÑÑÑенноÑÑи компоненÑа и пÑимениÑÑ Ðº ним локалÑнÑе ÑÑили.
ÐапÑимеÑ, ÑÑÐ¾Ñ <show-hello> ÑÐ»ÐµÐ¼ÐµÐ½Ñ Ð¿ÑÑÑÐµÑ Ñвой внÑÑÑенний DOM в Ñеневом деÑеве:
<script>
customElements.define('show-hello', class extends HTMLElement {
connectedCallback() {
const shadow = this.attachShadow({mode: 'open'});
shadow.innerHTML = `<p>
Hello, ${this.getAttribute('name')}
</p>`;
}
});
</script>
<show-hello name="John"></show-hello>
Ð Ð²Ð¾Ñ ÐºÐ°Ðº полÑÑивÑийÑÑ DOM вÑглÑÐ´Ð¸Ñ Ð² инÑÑÑÑменÑÐ°Ñ ÑазÑабоÑÑика в Chrome, веÑÑ ÐºÐ¾Ð½ÑÐµÐ½Ñ Ð²Ð½ÑÑÑи «#shadow-root»:
ÐÑак, вÑзов elem.attachShadow({mode: â¦}) ÑоздаÑÑ Ñеневое деÑево.
ÐÑÑÑ Ð´Ð²Ð° огÑаниÑениÑ:
- ÐÐ»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð³Ð¾ ÑлеменÑа Ð¼Ñ Ð¼Ð¾Ð¶ÐµÐ¼ ÑоздаÑÑ ÑолÑко один shadow root.
- РкаÑеÑÑве
elemÐ¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð¸ÑполÑзован полÑзоваÑелÑÑкий ÑÐ»ÐµÐ¼ÐµÐ½Ñ (Custom Element), либо один из ÑледÑÑÑÐ¸Ñ ÑлеменÑов: «article», «aside», «blockquote», «body», «div», «footer», «h1â¦h6», «header», «main», «nav», «p», «section» или «span». ÐÑÑалÑнÑе, напÑимеÑ,<img>, не могÑÑ ÑодеÑжаÑÑ Ñеневое деÑево.
СвойÑÑво mode задаÑÑ ÑÑÐ¾Ð²ÐµÐ½Ñ Ð¸Ð½ÐºÐ°Ð¿ÑÑлÑÑии. У него Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ ÑолÑко два знаÑениÑ:
-
"open"â коÑÐµÐ½Ñ Ñеневого деÑева («shadow root») доÑÑÑпен какelem.shadowRoot.ÐÑбой код Ð¼Ð¾Ð¶ÐµÑ Ð¿Ð¾Ð»ÑÑиÑÑ Ñеневое деÑево
elem. -
"closed"âelem.shadowRootвÑегда возвÑаÑаеÑnull.Ðо Ñеневого DOM в Ñаком ÑлÑÑае Ð¼Ñ Ñможем добÑаÑÑÑÑ ÑолÑко по ÑÑÑлке, коÑоÑÑÑ Ð²Ð¾Ð·Ð²ÑаÑаеÑ
attachShadow(и, ÑкоÑее вÑего, она бÑÐ´ÐµÑ ÑпÑÑÑана внÑÑÑи клаÑÑа). ÐÑÑÑоеннÑе бÑаÑзеÑнÑе ÑеневÑе деÑевÑÑ, Ñакие как Ñ<input type="range">, закÑÑÑÑ. Ðо Ð½Ð¸Ñ Ð½Ðµ добÑаÑÑÑÑ.
С возвÑаÑаемÑм меÑодом attachShadow обÑекÑом коÑнем Ñеневого деÑева, можно ÑабоÑаÑÑ ÐºÐ°Ðº Ñ Ð¾Ð±ÑÑнÑм DOM-ÑлеменÑом: менÑÑÑ ÐµÐ³Ð¾ innerHTML или иÑполÑзоваÑÑ Ð¼ÐµÑÐ¾Ð´Ñ DOM, Ñакие как append, ÑÑÐ¾Ð±Ñ Ð·Ð°Ð¿Ð¾Ð»Ð½Ð¸ÑÑ ÐµÐ³Ð¾.
ÐÐ»ÐµÐ¼ÐµÐ½Ñ Ñ ÐºÐ¾Ñнем Ñеневого деÑева назÑваеÑÑÑ â «Ñ
озÑин» (host) Ñеневого деÑева, и он доÑÑÑпен в каÑеÑÑве ÑвойÑÑва host Ñ shadow root:
// пÑи ÑÑловии, ÑÑо {mode: "open"}, инаÑе elem.shadowRoot Ñавен null
alert(elem.shadowRoot.host === elem); // true
ÐнкапÑÑлÑÑиÑ
Теневой DOM оÑделÑн Ð¾Ñ Ð³Ð»Ð°Ð²Ð½Ð¾Ð³Ð¾ докÑменÑа:
- ÐлеменÑÑ Ñеневого DOM не Ð²Ð¸Ð´Ð½Ñ Ð¸Ð· обÑÑного DOM ÑеÑез
querySelector. Ð ÑаÑÑноÑÑи, ÑлеменÑÑ Ñеневого DOM могÑÑ Ð¸Ð¼ÐµÑÑ Ñакие же иденÑиÑикаÑоÑÑ, как Ñ ÑлеменÑов в обÑÑном DOM (light DOM). Ðни Ð´Ð¾Ð»Ð¶Ð½Ñ Ð±ÑÑÑ ÑникалÑнÑми ÑолÑко внÑÑÑи Ñеневого деÑева. - У Ñеневого DOM Ñвои ÑÑили. СÑили из внеÑнего DOM не пÑименÑÑÑÑ.
ÐапÑимеÑ:
<style>
/* ÑÑили докÑменÑа не пÑименÑÑÑÑ Ð² Ñеневом деÑеве внÑÑÑи #elem (1) */
p { color: red; }
</style>
<div id="elem"></div>
<script>
elem.attachShadow({mode: 'open'});
// Ñ Ñеневого деÑева Ñвои ÑÑили (2)
elem.shadowRoot.innerHTML = `
<style> p { font-weight: bold; } </style>
<p>Hello, John!</p>
`;
// <p> виден ÑолÑко запÑоÑам внÑÑÑи Ñеневого деÑева (3)
alert(document.querySelectorAll('p').length); // 0
alert(elem.shadowRoot.querySelectorAll('p').length); // 1
</script>
- СÑили главного докÑменÑа не влиÑÑÑ Ð½Ð° Ñеневое деÑево.
- â¦Ðо Ñвои внÑÑÑенние ÑÑили ÑабоÑаÑÑ.
- ЧÑÐ¾Ð±Ñ Ð´Ð¾Ð±ÑаÑÑÑÑ Ð´Ð¾ ÑлеменÑов в Ñеневом деÑеве, нам нÑжно иÑкаÑÑ Ð¸Ñ Ð¸Ð·Ð½ÑÑÑи Ñамого деÑева.
СÑÑлки
- DOM: https://dom.spec.whatwg.org/#shadow-trees
- СовмеÑÑимоÑÑÑ: https://caniuse.com/#feat=shadowdomv1
- Теневой DOM ÑпоминаеÑÑÑ Ð²Ð¾ многиÑ
дÑÑгиÑ
ÑпеÑиÑикаÑиÑÑ
, напÑÐ¸Ð¼ÐµÑ DOM Parsing ÑказÑваеÑ, ÑÑо Ñ shadow root еÑÑÑ
innerHTML.
ÐÑого
Теневой DOM â ÑÑо ÑпоÑоб ÑоздаÑÑ Ñвой, изолиÑованнÑй, DOM Ð´Ð»Ñ ÐºÐ¾Ð¼Ð¿Ð¾Ð½ÐµÐ½Ñа.
shadowRoot = elem.attachShadow({mode: open|closed})â ÑоздаÑÑ Ñеневой DOM длÑelem. ÐÑлиmode="open", он доÑÑÑпен ÑеÑез ÑвойÑÑвоelem.shadowRoot.- ÐÑ Ð¼Ð¾Ð¶ÐµÐ¼ ÑоздаÑÑ Ð¿Ð¾Ð´ÑлеменÑÑ Ð²Ð½ÑÑÑи
shadowRootÑ Ð¿Ð¾Ð¼Ð¾ÑÑÑinnerHTMLили дÑÑÐ³Ð¸Ñ Ð¼ÐµÑодов DOM.
ÐлеменÑÑ Ñеневого DOM:
- ÐбладаÑÑ ÑобÑÑвенной облаÑÑÑÑ Ð²Ð¸Ð´Ð¸Ð¼Ð¾ÑÑи иденÑиÑикаÑоÑов
- ÐÐµÐ²Ð¸Ð´Ð¸Ð¼Ñ JavaScript ÑелекÑоÑам из главного докÑменÑа, Ñаким как
querySelector, - СÑилизÑÑÑÑÑ Ñвоими ÑÑилÑми из Ñеневого деÑева, не из главного докÑменÑа.
Теневой DOM, еÑли имееÑÑÑ, оÑÑиÑовÑваеÑÑÑ Ð±ÑаÑзеÑом вмеÑÑо обÑÑнÑÑ Ð¿Ð¾Ñомков (light DOM). Рглаве СлоÑÑ Ñеневого DOM, композиÑÐ¸Ñ Ð¼Ñ ÑазбеÑÑм, как делаÑÑ Ð¸Ñ ÐºÐ¾Ð¼Ð¿Ð¾Ð·Ð¸ÑиÑ.
ÐомменÑаÑии
<code>, Ð´Ð»Ñ Ð½ÐµÑколÑÐºÐ¸Ñ ÑÑÑок кода — Ñег<pre>, еÑли болÑÑе 10 ÑÑÑок — ÑÑÑÐ»ÐºÑ Ð½Ð° пеÑоÑниÑÑ (plnkr, JSBin, codepenâ¦)