Shadow DOM 与封装
在 Shadow Root 中隔离样式和标记。
Shadow DOM 与封装 是 CoddyKit 上的免费 JavaScript Academy 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 JavaScript Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 JavaScript Academy 课程共包含 4 节课。
什么是阴影 DOM
阴影 DOM 为元素提供一个私有且封装的 DOM 树。其中的标记和样式与页面的其他部分相互隔离。
- 外部 CSS 不会渗入其中。
- 内部 CSS 不会渗出到外部。
- 内部结构对普通 DOM 查询不可见。
attachShadow
您可以通过调用 this.attachShadow({ mode: 'open' }) 创建阴影树。它会返回一个阴影根,您可以像操作普通节点一样填充它。
class FancyBox extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
}
}
customElements.define('fancy-box', FancyBox);open 与 closed 模式
mode 选项控制外部访问方式:
'open'— 可以通过element.shadowRoot访问该根。'closed'—element.shadowRoot返回null;只有您的代码持有该引用。
大多数组件使用 'open',以便更轻松地调试。
const root = this.attachShadow({ mode: 'open' });
// Later, from outside:
// myEl.shadowRoot -> the shadow root (open)
// closed mode would give null here填充阴影根
设置 shadowRoot.innerHTML 来构建封装的内容。这些标记对 document.querySelector 不可见。
class FancyBox extends HTMLElement {
constructor() {
super();
const root = this.attachShadow({ mode: 'open' });
root.innerHTML = '<p>I live inside the shadow DOM</p>';
}
}
customElements.define('fancy-box', FancyBox);作用域样式
阴影根中的 style 标签只会影响该根。同一选择器在组件外部不会受到影响,页面样式也不会渗入其中。
root.innerHTML =
'<style>p { color: rebeccapurple; }</style>' +
'<p>Only this paragraph is purple.</p>';
// A <p> elsewhere on the page is NOT affected.:host 选择器
在阴影样式中,:host 选择自定义元素本身(即阴影树的宿主)。您可以使用它设置组件外部盒子的样式。
root.innerHTML =
'<style>' +
':host { display: block; border: 1px solid gray; }' +
':host(.active) { border-color: green; }' +
'</style>' +
'<slot></slot>';样式隔离的实际效果
封装意味着组件作者和页面作者不再需要争抢类名。一个组件内部的 .title 规则永远不会影响其他位置的 .title。
- 不会发生全局 CSS 冲突。
- 简单、通用的选择器重新变得安全。
查询阴影根内部
要访问内部节点,请查询阴影根,而不是文档。阴影根支持相同的查询方法。
class ToggleButton extends HTMLElement {
constructor() {
super();
const root = this.attachShadow({ mode: 'open' });
root.innerHTML = '<button>Off</button>';
this.btn = root.querySelector('button');
}
}
customElements.define('toggle-button', ToggleButton);事件跨越边界
许多事件(例如 click)会从阴影 DOM 冒泡出来,但会被重新定位,因此外部监听器看到的是宿主元素,而不是内部节点。这样可以保持封装性。
// Outside listener sees event.target as <toggle-button>,
// not the inner <button>.
document.querySelector('toggle-button')
.addEventListener('click', e => {
console.log(e.target.tagName); // TOGGLE-BUTTON
});可继承样式
少数 CSS 属性(例如 color 和 font-family)会跨越阴影边界继承,因为继承会沿着组合树向下传递。您可以依靠继承,或使用 CSS 自定义属性来采用页面的外观。
// :host { color: inherit; }
// CSS custom properties also pierce the boundary:
// :host { color: var(--text-color, black); }何时使用阴影 DOM
当可复用组件需要强大的样式和标记隔离时,可以考虑使用阴影 DOM。如果您希望组件自由继承并参与页面的全局样式,则不要使用它。
快速检查
检验您对阴影 DOM 的理解。
回顾
您已经了解了阴影 DOM:
attachShadow({ mode })会创建一个隔离的树。'open'会公开shadowRoot;'closed'会将其隐藏。- 内部的
style标签具有作用域;:host会设置元素本身的样式。 - 查询针对阴影根执行,而不是针对文档执行。
- 事件会被重新定位,以保持封装性。
接下来,我们将使用模板和插槽复用标记。
常见问题解答
「Shadow DOM 与封装」课时是免费的吗?
是的 — 「Shadow DOM 与封装」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 JavaScript Academy 课程的其余内容,请升级到 CoddyKit PRO。 JavaScript Academy 课程共包含 4 节课。
「Shadow DOM 与封装」这节课中我会学到什么?
在 Shadow Root 中隔离样式和标记。 你通过在浏览器中直接运行的动手代码来练习 JavaScript Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 JavaScript Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 JavaScript Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。
「Shadow DOM 与封装」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 JavaScript Academy 课中编写并运行代码吗?
能。每节 JavaScript Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。