slot匹配需严格字符串一致,大小写、空格、连字符等均不可差;仅直系子元素生效;name不支持动态绑定;具名与默认插槽互斥;多同名slot仅首个多生效;无slot声明则内容被丢弃。

slot name 属性必须严格字符串匹配
内容“消失”但控制台没报错,八成是 name 和 slot 属性值不完全一致。HTML 规范要求原生 <slot></slot> 的匹配是纯字符串比对,大小写、空格、连字符、下划线一个都不能差。
常见错误现象:
-
<slot name="header"></slot>不接收<h1 slot="Header"></h1>(首字母大写) -
<slot name="user-info"></slot>不接收<div slot="userinfo"></div>(缺连字符) -
<slot name="footer"></slot>不接收<p slot="footer "></p>(末尾空格)
调试建议:直接查 slotElement.assignedNodes() 返回是否为空数组。如果为空,说明没匹配上,别猜逻辑,先核对每一个字符。
slot 属性只对直系子元素生效
插槽分发不是深度遍历,只看自定义元素的**直接子节点**。哪怕 DOM 结构只多套一层 <div>,<code>slot 属性就彻底失效。
正确写法:<my-card><h2 slot="title">Hello</h2></my-card>
无效写法:<my-card><div><h2 slot="title">Hello</h2></div></my-card> —— <h2></h2> 是孙节点,被跳过
注意点:
- 框架如 Vue 的
v-slot是模拟机制,不受此限;但若组件底层用了attachShadow,仍要遵守这条 - 用 JS 动态插入节点时,必须确保插入的是 light DOM 直接子级,否则
slot属性不会被识别
name 属性不支持动态绑定
name 是静态 HTML 属性,不能写成 <slot :name="headerName"></slot>(Vue)或 <slot name="{{name}}"></slot>(模板语法)。这类写法在解析阶段就被当作文本字面量处理。
例如 Vue 模板中未用 v-bind:name,实际生成的 DOM 就是 <slot name="headerName"></slot> —— 引号里真是 “headerName” 五个字母,不是变量值。
可行方案:
- 预定义一组固定
name,比如header/sidebar/footer,再配合v-if或if控制显隐 - 用 JS 手动设置:先渲染无
slot属性的节点,再调el.setAttribute('slot', 'dynamic-name') - 服务端模板中拼接字符串(如
<slot name="${slotName}"></slot>)可生效,但这是构建时行为,非运行时响应
具名插槽与默认插槽的分发边界很硬
它们不是 fallback 关系,而是互斥通道:带 slot="xxx" 的内容,只尝试匹配 <slot name="xxx"></slot>,匹配失败也不会掉进默认插槽;没写 slot 属性的内容,只进第一个无 name 的 <slot></slot>。
容易被忽略的细节:
- 多个同名
<slot name="item"></slot>允许存在,但只有第一个能分发到内容,其余保持空 -
<slot name="aside">侧边栏默认内容</slot>中的 fallback 文本,仅在assignedNodes().length === 0时显示;哪怕有一个空的<div slot="aside"></div>,fallback 也不会出现 - 组件里如果既没写
<slot></slot>也没写任何<slot name="xxx"></slot>,所有传入内容都会被静默丢弃,DOM 中不可见也不可访问
最麻烦的从来不是语法报错,而是内容“看不见却没提示”——这时候优先查 assignedNodes()、确认节点层级、逐字符比对 name 和 slot 值。











