Shadow DOM 的 slot 是浏览器原生的内容投影机制,非父子通信;需通过 customElements.define 注册自定义元素并 attachShadow 启用,slot 仅在 shadowRoot 内生效,内容分发严格依赖直系子节点与 name 属性完全匹配,且需监听 slotchange 或延迟查询 assignedNodes。

Shadow DOM 中的 slot 插槽不是“父子组件通信”机制,而是浏览器原生的内容投影(content distribution)机制——它不依赖 JavaScript 逻辑传递数据,也不涉及 props 或事件绑定,而是由 DOM 引擎在渲染阶段自动将 light DOM 的子节点“投射”到 shadow root 内指定的 <slot> 位置。
必须启用 Shadow DOM 才能用 slot
slot 标签只在自定义元素的 Shadow DOM 内生效。普通 HTML 元素(如 <div>、<section>)里写 <slot> 完全无效,会被忽略。
- 先定义合法自定义元素:用 customElements.define('my-card', MyCard) 注册标签
- 在构造函数或 connectedCallback 中调用 this.attachShadow({ mode: 'open' })
- 把 slot 写进 shadowRoot 内部,例如:shadowRoot.innerHTML = '<header><slot name="title"></slot></header><main><slot></slot></main>'
内容必须是直系子节点,且 name 严格匹配
外部传入的内容不会“穿透”包裹层,也不会模糊匹配。slot 分发只看两件事:层级是否为直接子节点、属性值是否完全一致。
- ✅ 正确:<my-card><h2 slot="title">标题</h2><p>正文</p></my-card> → <h2>进具名插槽,<p>进默认插槽
- ❌ 错误:<my-card><div><h2 slot="title">标题</h2></div></my-card> → <h2>被丢弃(它是 <div> 的子节点,不是 <my-card> 的直系子节点)
- ❌ 错误:<h2 slot="Title"> 或 <h2 slot="title "> → name 值大小写或空格不一致,无法匹配 <slot name="title">
默认插槽和具名插槽的行为规则
一个组件里可以有多个 slot,但分发逻辑很明确,不是“广播”,而是“一对一”按顺序分配。
- 无 name 的 <slot> 是默认插槽,只接收所有未被具名 slot 拦截的第一个无 slot 属性的直系子节点(后续同级节点会被丢弃)
- 多个 <slot name="item"> 时,light DOM 中每个 <... slot="item"> 元素会依次填入——第一个元素进第一个 slot,第二个进第二个 slot
- slot 内可写 fallback 文本,例如 <slot>暂无内容</slot>,仅当外部完全没有匹配内容时才显示
查内容、监听变化要等时机
slot 分发发生在 DOM 解析完成之后,并非同步立即可用。刚插入元素时直接查,大概率为空。
- 获取已分发的内容:用 slotEl.assignedNodes()(含文本节点)或 slotEl.assignedElements()(仅元素)
- 监听内容变更:给 slot 元素加 slotchange 事件,它在分发完成或 light DOM 子节点动态增删后触发
- 不要在 connectedCallback 里立刻查 assignedNodes(),应等 slotchange 或用 requestAnimationFrame 延迟一次


















