shadow dom 是样式封装的唯一可靠路径,必须调用 this.attachshadow({ mode: 'open' }) 创建 shadow root,样式需内联于 shadow 内部,使用 :host 和 :slotted() 控制布局与插槽样式,并在 attributechangedcallback 中谨慎更新状态。

Shadow DOM 是样式封装的唯一可靠路径
不启用 Shadow DOM,所谓“模块化组件”只是 class 命名隔离,外部 CSS 仍能穿透(比如 body button { color: red } 会命中所有 button),根本谈不上封装。必须调用 this.attachShadow({ mode: 'open' }) 创建 shadow root,否则所有样式都在 light DOM,和普通 div 没区别。
推荐用 mode: 'open':方便调试(el.shadowRoot 可读)、支持 DevTools 查看、兼容性稳定;mode: 'closed' 虽防 JS 访问,但会让 shadowRoot 返回 null,连 console.log 都没法 inspect,实际开发中基本不用。
样式必须内联到 shadowRoot,不能靠 link 或外部 style
<link rel="stylesheet"> 在 shadow root 中完全无效——浏览器根本不解析它。所有样式必须以 <style></style> 标签形式注入 shadow 内部,例如:
shadow.innerHTML = `
<style>
:host { display: inline-block; }
.btn { padding: 8px 16px; background: #007bff; }
</style><button class="btn"><slot></slot></button>
`;
常见错误包括:
- 把
<style></style>写在组件外层 HTML 里,指望它作用于 shadow 内部 —— 失效 - 用
adoptedStyleSheets动态挂载 CSSStyleSheet —— Chrome 支持好,但 Safari 直到 2026 年仍存在部分 bug,不建议线上项目依赖 - 漏写
:host,导致组件自身无法响应外部设置的宽高、display 等布局属性
:slotted() 是控制插槽内容样式的唯一安全方式
<slot></slot> 本身不带样式边界,用户传入的 <h2 class="title">Hello</h2> 仍会被外部 CSS 影响。要限制这种穿透,只能用 :slotted() 选择器,在 shadow 内部主动约束:
-
:slotted(*) { all: initial; font-family: inherit; color: inherit; }—— 全局重置,慎用,可能清掉font-family -
:slotted(h2), :slotted(p) { margin: 0; line-height: 1.4; }—— 更稳妥,按需限定标签类型 - 避免在 slot 外套 div 再加 class 控制样式 —— 这等于把样式责任甩给使用者,违背封装初衷
注意::slotted(.my-class) 无效 —— 它不匹配 slot 内元素的 class,只匹配直接子元素的标签名或通配符。
attributeChangedCallback 里改样式必须走 class 或 style,别重写 innerHTML
组件响应 disabled、size 等属性变化时,不能在 attributeChangedCallback 里直接赋值 shadowRoot.innerHTML,否则会丢失用户插入的 <slot></slot> 内容,且触发完整重渲染。
正确做法是只更新局部状态:
- 声明监听:静态属性
static get observedAttributes() { return ['disabled', 'size']; } - 首次渲染补读:在
constructor或connectedCallback里用this.hasAttribute('disabled')判断初始值 - 回调内操作:
this.shadowRoot.querySelector('.btn').classList.toggle('disabled', newValue === 'true')或直接设style.opacity
真正容易被忽略的是:attributeChangedCallback 不会触发首次属性值(HTML 中写的 <my-button disabled></my-button>),必须手动补读 —— 这个坑几乎每个初学者都踩过一次。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











