slot不渲染的常见原因包括:未调用attachShadow()、自定义元素未合法注册、外部节点层级过深、slot name大小写不匹配、过早调用assignedNodes()未加{flatten:true}、未监听slotchange事件,以及::slotted()样式使用超出单层选择器限制。

slot 不是普通 HTML 标签,它只在自定义元素的 Shadow DOM 内生效,且必须配合 attachShadow() 使用;直接写在页面里、或塞进 <div> 里,完全没反应。
<h3>为什么<code>slot不渲染、内容没投射进来
常见错误是把自定义元素当普通容器用,比如:
<div> <my-card><h2 slot="title">Hello</h2></my-card> </div>
这本身没问题,但问题往往出在组件实现侧:
- 没调用
attachShadow({ mode: 'open' }),或调用对象不是通过customElements.define()注册的合法自定义标签(如<my-card></my-card>) - 外部传入的节点层级太深:
<my-card><div><h2 slot="title">Hello</h2></div></my-card>中,<h2></h2>是孙节点,不会被具名<slot name="title"></slot>匹配到 - name 值大小写不一致,比如
<slot name="Header"></slot>对应<h2 slot="header"></h2>—— 不匹配 - 在
connectedCallback里立刻查assignedNodes(),但此时分发尚未完成,返回空数组
assignedNodes() 返回空?怎么拿到真实内容
assignedNodes() 默认只返回“直系分配节点”,即 Light DOM 中**直接子节点**中被该 slot 拦截到的部分。跨多层 slot 嵌套、或 fallback 内容都不会包含在内。
立即学习“前端免费学习笔记(深入)”;
真正要拿到最终渲染进来的所有节点,得加参数:
slotElement.assignedNodes({ flatten: true })
另外,别依赖初始化时机获取内容:
- 监听
slotchange事件才是可靠方式:slot.addEventListener('slotchange', handler) - Firefox 63 以下不支持
slotchange,需降级用MutationObserver监听slot元素的childList -
flatten: true是关键,漏掉它,嵌套 slot 或 fallback 里的节点就“看不见”
::slotted() 样式为什么不起作用
::slotted() 只能作用于被分发进来的节点(即 Light DOM 中的内容),但它有硬性限制:
- 只能接受简单选择器,不能写
::slotted(div h2)或::slotted(.header > h2),只支持::slotted(h2)、::slotted([slot="title"])这类单层匹配 - 它无法穿透多层嵌套:如果外部传入的是
<article><h2>…</h2></article>,::slotted(h2)有效,但::slotted(article h2)无效 - 样式隔离是单向的:组件内
<style></style>默认不影响 slot 内容;但外部全局 CSS(如p { color: red; })仍会生效——这不是 bug,是规范行为
真正难的不是写对 <slot></slot>,而是理解“内容仍在 Light DOM、只是视觉上被投影”这个前提;所有事件绑定、样式穿透、节点查询逻辑,都得按这个模型来推演,否则很容易陷入“明明写了却没效果”的循环。



















