跳到主要内容

认识

一、认识


Web components 的一个重要属性是封装——可以将标记结构样式行为隐藏起来,并与页面上的其他代码相隔离,保证不同的部分不会混在一起,可使代码更加干净、整洁。其中,Shadow DOM 接口是关键所在,它可以将一个隐藏的、独立的 DOM 附加到一个元素上。

Shadow DOM 允许将隐藏的 DOM 树附加到常规的 DOM 树中。它以 shadow root 节点为起始根节点,在这个根节点的下方,可以是任意元素,和普通的 DOM 元素一样。

你可以使用同样的方式来操作 Shadow DOM,就和操作常规 DOM 一样——例如添加子节点、设置属性,以及为节点添加自己的样式(例如通过 element.style 属性),或者为整个 Shadow DOM 添加样式(例如在 <style> 元素内添加样式)。不同的是,Shadow DOM 内部的元素始终不会影响到它外部的元素(除了 :focus-within),这为封装提供了便利。

1.1 术语

Shadow DOM 相关的术语如下:

  • Shadow Host: 一个常规 DOM 节点,Shadow DOM 会被附加到这个节点上

  • Shadow Tree: Shadow DOM 内部的 DOM

  • Shadow Boundary: Shadow DOM 结束的地方,也是常规 DOM 开始的地方

  • Shadow Root: Shadow Tree 的根节点

1.2 优点

1.3 缺点

ShadowDom 是游离在DOM树之外的节点树,但是他的创建基于普通DOM元素(并不文档的DOM树),所有没有办法基于整个文档的DOM树来直接进行操作。如果要操作一个 ShadowDOM , 往往需要定位到 Shadow DOM 的宿主节点, 然后切换到 Shadow Root 中, 然后再选择 Shadow Root 中对应的节点。

二、语法


shadowRoot 作为隐藏的起始根节点, 同样可以插入 <link><style> 以及其他内置标签元素。不过需要注意的是: <link> 元素不会打断 shadow root 的绘制,因此在加载样式表时可能会出现未添加样式内容(FOUC),导致闪烁。

2.1 内置元素

<div id="app"></div>

<script>
const app = document.querySelector('#app');
const shadowDom = app.attachShadow({ mode: 'open'});

const div1 = document.createElement('div');
div1.classList.add('div1');
div1.innerHTML = 'shadowDom 元素内容'
const style = document.createElement('style');
style.textContent = `
.div1{
color: red;
}
`

const linkElem = document.createElement("link");
linkElem.setAttribute("rel", "stylesheet");
linkElem.setAttribute("href", "style.css");


shadowDom.appendChild(div1);
shadowDom.appendChild(style);
shadowDom.appendChild(linkElem);
</script>

2.2 自定义元素

<custom-element id="3" url="http"></custom-element>

<script>
class CustomElement extends HTMLElement{
constructor(){
super();

const shadow = this.attachShadow({ mode: "open" });
const wrapper = document.createElement('div');
wrapper.innerHTML = "自主定制元素"
wrapper.classList.add('wrapper');
const style = document.createElement('style');
style.textContent = `
.wrapper{
color: red;
}
`

console.log(this.getAttribute('id'));
console.log(this.hasAttribute('url'))

const linkElem = document.createElement("link");
linkElem.setAttribute("rel", "stylesheet");
linkElem.setAttribute("href", "style.css");

shadow.appendChild(wrapper);
shadow.appendChild(style);
shadow.appendChild(linkElem);
}
}

customElements.define('custom-element',CustomElement);
</script>