slot必须配合Shadow DOM才能工作,需调用this.attachShadow({mode:'open'});仅作用于直系子节点,name属性须严格字符串匹配;::slotted()仅支持单层选择器。

slot 必须配合 Shadow DOM 才能工作
写了 <slot> 却没渲染?大概率是因为没调用 this.attachShadow({ mode: 'open' })。原生 slot 不是 HTML 通用语法,它只在 Web Components 的 Shadow DOM 环境下被浏览器识别和分发。
常见误操作:
- 直接在普通
<div>里写<p slot="header">标题</p>→ 浏览器当无意义属性丢弃,不报错也不警告 - 自定义元素已注册,但构造函数里漏掉
attachShadow→ 所有传入内容静默消失(不是隐藏,是跳过渲染) - 用了
{ mode: 'closed' }→ 渲染正常,但 JS 无法通过element.shadowRoot访问,调试时容易误判为“slot 没生效”
slot 匹配只认直系子节点,中间不能嵌套
这是最常被忽略的硬性限制:slot 分发只检查自定义元素的**直接子节点**,不递归穿透。
正确写法:<my-card><h2 slot="header">Title</h2></my-card> → <slot name="header"> 能接收到
立即学习“前端免费学习笔记(深入)”;
错误写法:<my-card><div><h2 slot="header">Title</h2></div></my-card> → 整个 <h2> 被丢弃,因为 <div> 是直系子节点,而 <h2> 是它的后代
这意味着:组件使用者必须控制传入结构,组件作者无法靠 CSS 或 JS “绕过一层”去匹配内容。
具名 slot 的 name 和 slot 属性必须严格字符串匹配
<slot name="footer"> 只接收 <p slot="footer">©2026</p>,其余全部不匹配。大小写、空格、连字符都算不同字符串。
典型失效原因:
-
slot="Footer"(首字母大写)→ 不匹配name="footer" -
slot="footer "(末尾空格)→ 字符串不等,匹配失败 -
slot="footer-text"(多一个连字符)→ 不等于"footer"
默认插槽(无 name)也只接收第一个无 slot 属性的直系子节点;后续同级无属性节点不会塞进第二个空 <slot>,而是直接丢弃。
::slotted() 只支持单层选择器,深层样式得另想办法
::slotted() 是唯一能从 Shadow DOM 内部影响投射内容的样式机制,但它只匹配被分发进来的**直系子元素**,不支持后代选择器或伪类。
可行写法:
::slotted(h2)::slotted([slot="footer"])::slotted(.btn)
无效写法:
-
::slotted(div h2)(后代选择器) -
::slotted(h2:hover)(伪类) -
::slotted(*)(通配符无效)
如果需要控制嵌套更深的节点,得让外部传入内容自带 class,或在组件内用 slot.assignedNodes() 手动遍历处理——这是真正需要动手的地方,不是加个样式就能解决的。



















