::part()仅能样式化组件内部显式标记part属性的节点,大小写敏感且不支持链式选择;::slotted()则专用于样式化slot投射的外部内容直接子元素,两者作用域、编写位置及使用主体均不同。

::part() 只能样式化组件内部显式暴露的节点
它不是穿透工具,而是“按名索引”机制:外部 CSS 写 ::part(loader),组件 shadow 内必须有对应元素带 part="loader" 属性,缺一个字母或大小写不一致就完全失效。浏览器不会报错,只是静默忽略。
常见错误现象:
-
::part(icon)生效不了 → 组件里实际写的是part="icon-slot"或part="Icon" - 试图链式写
::part(wrapper) input或::part(label)::before→ 语法非法,::part()后不能接其他选择器 - 在同一个 shadow tree 里写
::host::part(label)→ 无效,::part()只能在 light DOM 或父级 shadow 中使用
必须由组件作者主动加 part 属性,调用方无法绕过。比如想定制加载动画颜色,组件内部得这样写:<div part="loader" class="spinner"></div>,否则你写再多 CSS 都没用。
::slotted() 专用于样式化被 slot 投射进来的外部内容
它匹配的是从 light DOM 传入、经 <slot></slot> 分发后渲染在 shadow 内的**直接子元素**,不是 shadow 自己的节点。例如你写 <my-card><h2 slot="title">Hello</h2></my-card>,组件内部用 <slot name="title"></slot> 接收,那么 ::slotted([slot="title"]) 就能选中那个 <h2></h2>。
注意限制:
- 只作用于 slot 的**直接子元素**,不能选中
<h2><span>Hello</span></h2>里的<span></span> - 样式规则写在 shadow 内部(即组件自己的
<style></style>),不是外部 CSS - 支持属性选择器如
::slotted([slot="icon"]),但不支持伪类如::slotted(:hover)
两者作用域和时机完全不同
::part() 是“组件对外暴露定制点”,目标是 shadow 内部节点,由调用方写在外部样式表;::slotted() 是“组件控制投射内容样式”,目标是外部传入的内容,由组件作者写在 shadow 内部样式中。
典型场景对比:
- 你想改
<my-button><svg slot="icon"></svg></my-button>里那个<svg></svg>的颜色 → 用::slotted([slot="icon"]) - 你想改按钮内部那个旋转
<div part="spinner"></div>的动画色 → 用my-button::part(spinner)
它们不互斥,常配合使用:组件暴露 part 控制自身结构,用 ::slotted() 管理外部内容表现。
兼容性与实际落地要点
::part() 在 Chrome 97+、Edge 97+、Safari 16.4+ 可用,Firefox 仍无计划支持;::slotted() 兼容性好得多(Chrome 53+ 起就支持)。
真正容易被忽略的是 closed shadow root 场景:如果组件用了 attachShadow({ mode: 'closed' }),即使它暴露了 part,外部 ::part() 也完全不可用——这个限制无法绕过,只能确认组件是否为 open 模式。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











