是web components中实现内容分发的唯一标准机制,仅在启用shadow dom的自定义元素内有效,依赖attachshadow()、严格匹配的name与slot属性、运行时分发,不支持ssr且需监听slotchange事件获取节点。

<slot></slot> 就是 Web Components 中内容分发(content distribution)的实现机制,不是“有关系”,而是“它就是”——没有 <slot></slot>,就没有标准的、声明式的内容分发。
为什么直接写 <slot></slot> 在普通 HTML 里没用
浏览器把 <slot></slot> 当作未知标签处理,既不报错也不渲染内容,更不会分发任何东西。它只在启用 Shadow DOM 的自定义元素内部起作用。
- 必须通过
customElements.define()注册一个自定义标签(如<my-card></my-card>) - 在该元素的
constructor或connectedCallback中调用this.attachShadow({ mode: 'open' }) -
<slot></slot>必须出现在这个 shadowRoot 的模板或 innerHTML 中,才具备分发能力 - 常见错误:
Failed to execute 'attachShadow' on 'Element': This element does not support shadow roots—— 说明你试图给<div> 或 <code><p></p>挂载 Shadow DOM,这是不允许的具名插槽
name和外部slot属性必须严格一致大小写、连字符、空格,一个都不能错。不匹配的内容会掉进默认插槽(如果存在),或被完全忽略。
-
<slot name="header"></slot>只接收<h2 slot="header">标题</h2> -
<h2 slot="Header"></h2>或<h2 slot=" header "></h2>都不会命中 - 未带
slot属性的子节点,会进入第一个(也是唯一一个)匿名<slot></slot>;但若组件内没有匿名<slot></slot>,这些节点就彻底“消失”——不渲染、不报错、不触发事件
SSR 场景下
<slot></slot>内容永远为空服务端根本不知道父组件传了什么进来。
<slot></slot>是运行时机制,不是模板占位符。SSR 输出的 HTML 里,<slot></slot>标签位置只会显示其 fallback 文本(如果有),其余全是空白。- SEO 爬虫看到的是空区域,不是你期望的标题/正文
- CDN 缓存的也是这个空白模板,首屏 LCP 极易被拖慢
- 解决方案不是“修复插槽”,而是:给
<slot></slot>加 fallback(如<slot>Loading...</slot>),或改用服务端可识别的结构(如属性传值 + 客户端补全) - 不要指望
slotchange在 SSR 阶段触发——它只在客户端 DOM 分发完成时发生
assignedNodes()返回空数组?别急着查在
connectedCallback里立刻调用shadowRoot.querySelector('slot').assignedNodes(),大概率拿到空数组。因为此时 Light DOM 还没解析完,内容尚未分发。- 正确做法:监听
slotchange事件,等它触发后再读取 - 要用
assignedNodes({ flatten: true })才能拿到所有最终投射进来的节点;否则只返回直系分配结果,跨多层 slot 会漏掉内容 -
<slot></slot>分发的是节点引用,不是响应式代理——父组件改了数据,插槽里静态 HTML 不会重渲染
真正容易被忽略的点是:插槽分发发生在 DOM 构建后期,且完全脱离 HTML 解析流程。这意味着它和 SEO、CDN、预加载器、服务端缓存全部天然不兼容。想用插槽,就得接受它是纯客户端机制——不能靠它承载关键首屏内容,也不能指望它提升分发效率。
-











