未渲染的主因是自定义元素shadow DOM中缺失或传入内容非light DOM直接子节点;name属性需字面量精确匹配且大小写敏感;分发异步,须用assignedNodes()或监听slotchange事件检测。

Web Components 的 <slot></slot> 不是 Vue 或 React 那套响应式插槽,它原生、静态、靠 DOM 树位置和 name 属性匹配,不支持作用域、不触发重新渲染,用错就显示空白。
为什么 <slot></slot> 什么都没渲染出来
最常见的原因是:自定义元素内部没写 <slot></slot>,或者外部传入的内容没被浏览器识别为“可分发节点”——比如内容在 <template></template> 里、或被 JS 动态 append 进去但没触发 slot 分发(slotchange 事件不会自动重算)。
- 确保自定义元素的 shadow DOM 中至少有一个
<slot></slot>,哪怕只是<slot></slot>(默认插槽) - 传入内容必须是 light DOM 的直接子节点,例如:
<my-card><h2>标题</h2> <p>正文</p></my-card>,不能包在<div> 里再塞进去 <li>如果用 JS 动态添加内容,需调用 <code>element.appendChild()后手动触发slot.assignedNodes()检查是否已分发,必要时用requestIdleCallback延迟读取 - 外部节点必须显式写
slot="xxx",例如:<h1 slot="header">欢迎</h1> - 多个同名
slot属性会被合并到同一个命名插槽,顺序按 light DOM 中出现顺序 - 没匹配上的节点会落到默认插槽(无
name的<slot></slot>),如果没有默认插槽,那些节点就“消失”——不是隐藏,是根本不会出现在 shadow DOM 中 -
slot属性只能用于 light DOM 直接子节点,嵌套一层就不认了 - 监听
slotchange事件:shadowRoot.querySelector('slot').addEventListener('slotchange', () => { ... }) - 读取分发结果用
slot.assignedNodes({ flatten: true }),flatten: true能展开命名插槽里的 fallback 内容 - 注意:
assignedNodes()返回的是 live NodeList,但修改它不影响分发结果;想改内容得操作 light DOM 原节点 - 服务端渲染或 SSR 场景下,
<slot></slot>不起作用——因为没运行 JS、没 attach shadow DOM,此时 fallback 内容(<slot>fallback</slot>里的文本)才会显示
name 属性怎么配才生效
name 是字符串匹配,大小写敏感,且只认属性值字面量,不支持表达式或绑定。一个 <slot name="header"></slot> 只会接收 light DOM 中带 slot="header" 的元素。
如何检测插槽内容是否已分发
不能靠 innerHTML 或 childNodes 查 shadow DOM,得用 slot API。分发是异步的,DOM ready 后也不一定立刻完成。
最易忽略的一点:slot 分发发生在浏览器 layout 阶段之前,但不保证与 custom element constructor 或 connectedCallback 同步。如果你在 connectedCallback 里立刻调 slot.assignedNodes(),大概率拿到空数组——得用 Promise.resolve().then() 或 requestAnimationFrame 延后一帧再读。

















