slot标签只在shadow dom中生效,普通html中无效;需调用attachshadow()、确保light dom直系子节点匹配具名插槽字符串、理解投影机制及::slotted()限制。

slot 标签为什么写了却没渲染内容
不是代码写错了,是机制根本没启动。slot 只在 Shadow DOM 中生效,普通 HTML 里写 <slot></slot> 完全无效,浏览器当它不存在。
常见静默失败路径:
- 自定义元素构造函数里没调
this.attachShadow({ mode: 'open' }) -
slot标签被写在 Light DOM(比如直接塞进<my-card></my-card>标签内部) - 用了
{ mode: 'closed' },导致 JS 无法访问shadowRoot,调试时误判为“没生效” - 外部内容不是直系子节点,例如
<my-card><div><h2 slot="title">Hi</h2></div></my-card>——<h2></h2>被<div> 隔开,直接丢弃 <h3>具名插槽 name 属性必须严格字符串匹配</h3> <p><code>slot="footer"和<slot name="footer"></slot>才能配对。大小写、空格、连字符,一个都不能错。典型失效案例:
-
slot="Footer"→ 大小写不一致,不匹配 -
slot="footer "→ 末尾多一个空格,不匹配 -
slot="footer-text"→ 多了连字符,不匹配 -
<slot name="header"></slot>和<h2 slot="Header"></h2>→ 匹配失败,内容丢弃
默认插槽(无
name)也只接收第一个无slot属性的直系子节点;后续同级节点不会被塞进第二个空<slot></slot>,而是直接跳过渲染。::slotted() 伪类只能选直系投射节点
::slotted()不是普通 CSS 选择器,它只作用于被投射进来的 Light DOM 直系子元素,不支持后代、伪类或通配符。能用的写法:
::slotted(h2)::slotted([slot="footer"])::slotted(.btn)
不能用的写法:
-
::slotted(div h2)→ 后代选择器无效 -
::slotted(h2:hover)→ 伪类无效 -
::slotted(*)→ 通配符不被支持
想控制深层结构?要么让使用者自己加
class,要么用 CSS 自定义属性透传,比如--card-title-color。slot 分发不移动节点,只做视觉投影
slot的本质是投影(projection),不是移动。Light DOM 中的节点始终保留在原处,只是浏览器在渲染阶段把它们“画”到slot占位位置。这意味着:-
slot.assignedNodes()返回的是原始节点引用,改它的className会立刻反映在页面上 - 未匹配的节点仍存在于 Light DOM 中,但完全不参与布局和渲染(不是
display: none,是彻底跳过) - 后备内容(fallback)只在对应
slot没收到任何节点时才显示;哪怕 Light DOM 里只有一个空格文本节点,也算“有内容”,fallback 就不会出现 - 分发发生在渲染前的 DOM 投影阶段,不是 JS 运行时行为——你不能靠
querySelector在 Light DOM 里找“已被 slot 接收”的节点,它压根没动过位置
真正容易被忽略的,是它既不报错也不警告。内容“消失”时,得同时检查四件事:自定义元素是否注册、
attachShadow()是否执行、Light DOM 结构是否合规、slot和slot属性的字符串是否一字不差。 -











