slot标签是浏览器原生的Shadow DOM内容分发机制,本质为投影而非移动:Light DOM节点保留在原处,仅视觉投射到slot位置;未匹配节点被静默丢弃,不报错、不渲染。

slot 标签本身不“移动”内容,它只是浏览器在 Shadow DOM 渲染阶段执行的一次投影(projection)映射——Light DOM 中的节点仍保留在原处,只是视觉上被“投射”到 slot 占位位置。
为什么slot不渲染、内容却“消失”了
这不是 bug,而是机制设计:未匹配的 Light DOM 子节点会被丢弃(不报错、不显示、不参与布局)。常见原因包括:
- 自定义元素没调用
this.attachShadow({ mode: 'open' }),slot根本不进入分发流程 - 外部内容不是直系子节点,比如
<my-card><div><h2 slot="header">标题</h2></div></my-card>——<h2>被<div>隔开,直接忽略 -
<slot name="header"></slot>和<h2 slot="Header">大小写不一致,字符串比对失败 - 写了多个无
name的<slot>,只有第一个接收内容,其余被静默跳过
slot 的后备内容(fallback)什么时候生效
后备内容只在对应 slot 完全没有接收到任何节点时才显示。注意几个边界情况:
- 哪怕 Light DOM 里只有一个空格文本节点(
),也会被当作“有内容”,后备文案不显示 -
<slot>默认文案</slot>中的“默认文案”是 Light DOM 片段,它本身不会出现在最终渲染树中,只作为 fallback 存在 - 具名
slot的 fallback 不会“兜底”给其他 slot,<slot name="footer">©2026</slot>和<slot>主内容</slot>互不影响
::slotted() 为什么只能选直系子元素
这是浏览器强制的限制,不是 CSS 选择器能力不足:::slotted(*) 可以匹配所有投射进来的节点,但 ::slotted(div p) 无效,因为投射关系只存在于 Light DOM 子节点与 slot 之间,中间不经过 Shadow DOM 层级。
立即学习“前端免费学习笔记(深入)”;
- 样式作用域仍属于 Light DOM 上下文,
::slotted()是唯一能穿透投射边界影响 Light DOM 节点样式的伪元素 - 如果想控制更深层结构,必须让使用者自己加 class,或通过 CSS 自定义属性(
--my-card-header-color)透传 -
slot.assignedNodes()返回的是真实 Light DOM 节点引用,不是副本——改它的className会立刻反映在页面上
真正容易被忽略的是:slot 分发发生在 DOM 渲染前的“投影阶段”,不是 JS 运行时行为。这意味着你不能靠 querySelector 在 Light DOM 里找“已被 slot 接收”的节点——它压根没动过位置,只是被浏览器画到了别处。


















