是Web Components中内容分发的唯一标准机制,无插槽则无声明式内容分发;外部子节点默认不渲染,须通过插入Shadow DOM指定位置,具名与匿名插槽按属性匹配分发,需监听slotchange事件响应动态变化。

HTML 插槽(<slot></slot>)本身不“配合”内容分发,它就是 Web Components 中内容分发(content distribution)的唯一标准机制——没有插槽,就没有真正的、声明式的、可组合的内容分发。
为什么 <slot></slot> 是内容分发的强制入口
在自定义元素中,外部传入的子节点默认不会自动渲染;它们被暂存在 assignedNodes() 中,直到遇到 <slot></slot> 才被插入到 Shadow DOM 的指定位置。没写 <slot></slot>,传进去的 HTML 就是“看不见的死节点”。
常见错误现象:
- 自定义按钮组件里写了
<my-button>点击我</my-button>,但 Shadow DOM 里没放<slot></slot>→ 页面只显示空盒子 - 写了
<slot name="icon"></slot>,但外部用<my-card><span slot="icon2">★</span></my-card>→ 图标不出现(slot属性值不匹配)
<slot></slot> 的 name 和匿名插槽怎么选
匿名插槽(无 name)接收所有未指定 slot 属性的子节点;具名插槽只接收 slot 属性值完全匹配的节点。二者不能混用覆盖——一个节点只能被一个插槽接收。
立即学习“前端免费学习笔记(深入)”;
使用场景建议:
- 组件主体内容(如卡片正文、对话框文字)用匿名插槽,最灵活
- 固定位置的装饰性内容(如标题栏左侧图标、右上角关闭按钮)用具名插槽,语义清晰
- 避免多个匿名插槽:浏览器只把未分配节点塞给第一个匿名插槽,后面的会被忽略
示例:
<!-- 组件模板 --> <div class="card"> <header><slot name="header">默认标题</slot></header> <main><slot>默认正文</slot></main> <footer><slot name="footer"></slot></footer> </div>
如何响应插槽内容变化(slotchange 事件)
插槽内容不是静态的:用户可能动态增删子节点、切换 slot 属性、甚至用 innerHTML 替换整个 Light DOM。这时需要监听 slotchange 事件来更新逻辑(比如统计图标数量、校验必填项)。
关键点:
- 事件触发在
<slot></slot>元素上,不是自定义元素本身 - 必须在
connectedCallback中绑定,且注意移除旧监听器(避免重复绑定) -
event.target.assignedNodes({ flatten: true })才能拿到最终渲染的节点(含跨级分布式内容)
容易踩的坑:直接读 slot.childNodes → 返回空 NodeList,因为内容不在 <slot></slot> 内部,只是“投影”过去。
兼容性与性能提醒
<slot></slot> 是 Shadow DOM v1 规范的一部分,Chrome 53+、Firefox 63+、Safari 10.1+ 支持;Edge 79+(Chromium 版)没问题,但旧 Edge 完全不支持。
性能影响很小,但要注意:
- 大量具名插槽 + 频繁变更
slot属性 → 触发多次slotchange,可能造成重排 - 在
slotchange回调里直接操作 DOM(如appendChild)可能引发循环分发,建议用requestAnimationFrame节流 - 服务端渲染(SSR)时,
<slot></slot>不起作用——内容只会按 Light DOM 原样输出,Shadow DOM 根本没生成
真正难的从来不是怎么写 <slot></slot>,而是想清楚哪些内容该暴露为插槽、哪些该封装进组件内部逻辑——边界划错,再标准的分发机制也救不了设计缺陷。



















