slot属性仅做大小写敏感字符串匹配,匹配成功后light dom节点以引用形式投影到shadow dom的位置;常见不显示原因是大小写不一致、节点非直系子元素、未调用attachshadow、多个无name slot仅首个多余为空;验证需用slotchange事件和assignednodes({flatten:true});::slotted()仅匹配直系子节点且不可查。

slot 属性本身不传数据,也不移动节点——它只是浏览器做一次大小写敏感的字符串匹配,匹配成功后,Light DOM 节点以引用形式“投影”到 Shadow DOM 的 <slot></slot> 位置。
slot 属性为什么写了却没显示内容
最常见原因不是样式或 JS 错误,而是分发契约根本没对上:
-
slot="header"和<slot name="Header"></slot>大小写不一致 → 匹配失败,内容被静默丢弃 - 外部节点被包裹了一层,比如
<my-card><section><h2 slot="header">标题</h2></section></my-card>→<h2></h2>是孙节点,不是直系子元素,直接忽略 - 自定义元素没调
this.attachShadow({ mode: 'open' })→slot属性在普通 DOM 中纯属无效字符串,浏览器不处理 - 写了多个无
name的<slot></slot>→ 只有第一个接收未匹配内容,其余全空
如何验证内容是否真被分发进来
别只靠肉眼或 querySelector 看渲染结果,因为投影不改变节点物理位置:
-
slot.assignedNodes()返回的是原始 Light DOM 节点引用,但必须等分发完成才能读取;在connectedCallback里直接调,大概率返回空数组 - 正确时机是监听
slotchange事件:shadowRoot.querySelector('slot[name="header"]').addEventListener('slotchange', () => { ... }) - 需要获取嵌套结构(比如 fallback 里的内容)时,必须传
{ flatten: true },否则只返回直系分配节点 - Firefox 63 以下不支持
slotchange,得用MutationObserver监听slot元素的childList
::slotted() 样式为什么不起作用
因为它的匹配能力被浏览器严格限制,不是选择器写错了,而是规则本身就不支持深层穿透:
-
::slotted(h2)✅ 有效;::slotted(div h2)❌ 无效 —— 只能匹配投射进来的**直系子节点**,中间不能有层级 -
::slotted([slot="footer"])✅ 可用;::slotted(.footer h2)❌ 不生效 - Light DOM 内容默认不受 Shadow DOM 样式隔离保护,外部全局 CSS 依然生效;想控制它,必须显式用
::slotted()或 CSS 自定义属性 -
shadowRoot.querySelector('::slotted(h2)')永远返回null——::slotted()是伪元素,不是真实可查的 DOM 节点
真正容易被忽略的,是分发发生在浏览器渲染流水线的投影阶段,不是 JS 同步执行的结果;你改了节点的 textContent,它立刻反映在投影位置,是因为操作的是同一个对象,而不是副本——这点决定了所有响应式更新和事件冒泡都走 Light DOM 路径,跟 shadowRoot 无关。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











