同名slot按DOM顺序一对一匹配:Light DOM中每个slot="xxx"的直系子节点依次填入Shadow DOM中对应顺序的<slot name="xxx">,数量不匹配则多余节点被丢弃或空slot保留;匹配严格区分大小写、空格和连字符,且仅限直系子元素;分发异步发生,需监听slotchange事件获取assignedNodes()。

多个同名 <slot name="xxx"> 怎么分发内容?
不是广播,也不是合并,而是顺序一对一匹配。Light DOM 中每个带 slot="xxx" 的直系子节点,按 DOM 顺序依次填入 Shadow DOM 中每一个同名 <slot name="xxx"> —— 第一个节点进第一个 slot,第二个节点进第二个 slot,以此类推。
常见错误现象:<my-list><div slot="item">A</div><div slot="item">B</div></my-list>,组件内却只写了一个 <slot name="item"></slot>,结果 B 被丢弃(因为没对应 slot 接收);反过来,如果写了三个 <slot name="item"> 但只传一个节点,后两个 slot 就始终为空。
- 必须保证 Light DOM 中
slot="xxx"节点数量 ≥ 同名 slot 元素数量,否则末尾 slot 无内容 - 节点顺序严格按 Light DOM 子节点顺序,不是按插入时间或 JS 动态添加顺序
- 不支持“复用同一节点到多个 slot”,每个 slot 拿到的是不同节点的引用(不是克隆)
slot name 大小写/空格/连字符不一致导致分发失败
浏览器做纯字符串比对,name="Header" 和 slot="header" 完全不匹配。不 trim、不转小写、不 fallback —— 匹配失败的内容会被静默丢弃(除非有默认 <slot> 接收)。
调试建议:在 DevTools 中选中 slot 元素,执行 slot.assignedNodes(),返回空数组就说明没匹配上。再检查外部节点的 slot 属性值是否与 slot 的 name 完全一致(包括大小写、连字符、空格)。
立即学习“前端免费学习笔记(深入)”;
-
<slot name="user-avatar"></slot>只匹配<img slot="user-avatar">,不匹配<img slot="userAvatar">或<img slot="user-avatar "> - Vue/React 模板中写
<slot :name="headerName">是无效的 —— 渲染后name是字面量字符串,不是变量值 - 服务端模板或 JS 字符串拼接可动态生成 name,但客户端 HTML 解析阶段已固定,无法运行时变更
为什么 slot.assignedNodes() 在 connectedCallback 里总是空?
内容分发不是同步完成的。DOM 插入和 slot 匹配发生在浏览器渲染流水线后期,JS 在自定义元素连接时还来不及完成分发。
正确做法是监听 slotchange 事件,且必须绑定到具体 slot 元素上:
const slot = this.shadowRoot.querySelector('slot[name="title"]');
slot.addEventListener('slotchange', () => {
console.log(slot.assignedNodes({ flatten: true }));
});
注意:slotchange 不冒泡,不能在 shadowRoot 上监听;首次渲染不触发,只响应后续增删;若要获取 fallback 内容或深层投射节点,必须传 { flatten: true }。
嵌套结构里 slot 为什么不生效?
slot 只认自定义元素的**直系子元素**。哪怕只多包一层 <div>,节点就变成孙节点,浏览器直接跳过匹配 —— 不报错、不警告、不 fallback。
例如:<my-card><div><h2 slot="title">标题</h2></div></my-card> 中的 <h2> 不会进入 <slot name="title">,assignedNodes() 返回空数组。
- 确保外部使用时,带
slot属性的节点是自定义元素的直接子节点 - 如果业务逻辑必须包裹,得靠 JS 手动遍历 Light DOM 子节点,提取符合条件的节点再 append 到 shadowRoot 对应位置
-
::slotted()样式也受此限制:只能选直系子节点,::slotted(div h2)这类后代选择器完全无效
assignedNodes(),后者让内容“明明写了 slot 却不显示”——看起来像 bug,其实是规则本身如此。



















