slot标签仅在shadow dom中生效,必须通过attachshadow()启用;内容须为直系子节点且具名插槽严格字符串匹配;::slotted()仅支持单层选择器,分发发生在渲染前,查结果需用slot.assignednodes()。

slot 标签只在 Shadow DOM 中生效,否则内容被丢弃
写了 <slot></slot> 却没渲染出任何内容?不是 bug,是机制未启动。slot 是浏览器原生的投影机制,**必须配合 attachShadow() 才能工作**。普通 HTML 元素(比如 <div><slot></slot></div>)里的 <slot></slot> 完全无效,会被当作无意义标签忽略。
常见错误现象:<my-card><h2 slot="title">Hello</h2></my-card> 渲染为空白。排查路径很明确:
- 检查自定义元素构造函数里是否调用了
this.attachShadow({ mode: 'open' }) - 确认
shadowRoot.innerHTML或shadowRoot.appendChild()中确实包含<slot name="title"></slot> - 确保该自定义元素已通过
customElements.define()正确注册并升级
外部内容必须是直系子节点,隔层就丢弃
slot 匹配只认“直接子节点”,中间不能有包裹层。这是最容易被忽略的硬性限制。
例如:<my-card><h2 slot="header">Title</h2></my-card> ✅ 能命中 <slot name="header"></slot>;但 <my-card><div><h2 slot="header">Title</h2></div></my-card> ❌ 整个 <h2></h2> 被静默丢弃——<div> 是直系子节点,而 <code><h2></h2> 是它的后代,slot 不处理。
这意味着:传入内容的结构必须由使用者控制,组件作者无法“穿透”一层去匹配。
具名插槽严格字符串匹配,大小写/空格都不容错
<slot name="footer"></slot> 只接收 <p slot="footer">©2026</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill5493" title="html-to-pptx"><img
src="https://img.php.cn/upload/skill/000/000/081/179051045119472.jpg" alt="html-to-pptx" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/skill5493" title="html-to-pptx" class="overflowclass">html-to-pptx</a>
<p class="overflowclass">将多页 HTML 演示文稿转换为美化的 PPTX 文件,便于分享和分发。</p>
</div>
<a rel="nofollow" href="/xiazai/skill5493" title="html-to-pptx" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div>,其余全部不匹配。常见失效原因包括:
-
slot="Footer"(大小写不一致) -
slot="footer "(末尾空格) -
slot="footer-text"(多一个连字符) - 多个同名
<slot name="icon"></slot>,只有第一个能分发到内容,其余留空
默认插槽(无 name)也只接收**第一个**无 slot 属性的直系子节点;后续同级无属性节点不会被塞进第二个默认 <slot></slot>,而是直接丢弃。
::slotted() 仅支持单层选择器,深层样式得靠自定义属性
想给插槽里的按钮统一设色?::slotted(.btn) 可以,但 ::slotted(.btn:hover) 或 ::slotted(div .text) 全部无效。浏览器强制限制它只能匹配投射进来的**直系子元素**,不支持后代选择器或伪类。
更稳定的做法是透传 CSS 自定义属性:
/* 在 shadowRoot 样式中 */
:host {
--card-header-color: #333;
}
::slotted(h2) {
color: var(--card-header-color);
}
然后使用者只需在传入的 <h2></h2> 上不加 class,也能受控——这比依赖 ::slotted() 的选择能力更可靠。
真正容易被忽略的是:slot 分发发生在 DOM 渲染前的投影阶段,不是 JS 运行时行为。你用 querySelector 在 light DOM 里永远找不到“已被 slot 接收”的节点——它根本没动过位置,只是被画到了别处。要查投递结果,得用 slot.assignedNodes()。










