slot标签仅在Shadow DOM中生效,需自定义元素注册、调用attachShadow()、内容为直系子节点且name严格匹配,否则内容被丢弃不报错。

slot 标签本身不预留插槽——它只在 Shadow DOM 中生效,且必须配合自定义元素、attachShadow() 和正确的节点层级才能触发内容分发。 直接写 <slot></slot> 在普通 HTML 里,或塞进 <div> 里,浏览器会忽略它,不报错也不警告。
为什么写了 <slot> 却没显示内容?
常见现象是页面空白、DOM 中看不到投射内容,但控制台无报错。根本原因不是语法写错,而是机制未启动:
- 自定义元素未用
customElements.define()注册,比如直接对<p>调attachShadow()会抛DOMException: This element does not support shadow roots - 没调
this.attachShadow({ mode: 'open' })—— 缺这一步,<slot>就是普通文本标签 -
<slot>写在 Light DOM(如<my-card><slot></slot></my-card>)里,而非 Shadow DOM 内部模板中 - 用了
{ mode: 'closed' },导致 JS 无法访问shadowRoot,调试时误判为“没生效”
如何让外部内容真正进入 <slot>?
内容分发不是“自动扫描”,而是严格按规则匹配直系子节点:
- 外部内容必须是自定义元素的**第一层子节点**:
<my-card><h2 slot="header">Title</h2></my-card>✅;<my-card><div><h2 slot="header">Title</h2></div></my-card>❌(<h2>是孙节点) - 换行符和空格也算节点:
<my-card>\n<h2 slot="header">Title</h2>\n</my-card>中,第一个子节点是文本节点(换行),<h2>实际是第二个子节点,匹配失败 - 具名插槽的
name和slot属性值必须**字面量完全一致**:<slot name="footer"></slot>只接收<p slot="footer">©2026</p>,slot="Footer"、slot="footer "(末尾空格)、slot="footer-text"全部失效 - 默认插槽(无
name)只收**第一个**无slot属性的直系子元素;后续同级无属性节点被静默丢弃
怎么确认内容真被分配进去了?
别只看渲染结果——很多问题表面“显示了”,实则 assignedNodes() 返回空数组。可靠验证方式是监听 slotchange 事件:
立即学习“前端免费学习笔记(深入)”;
slot.addEventListener('slotchange', () => {
console.log(slot.assignedNodes({ flatten: true }));
});注意:
-
slotchange不冒泡,不能在shadowRoot上监听,必须绑定到具体<slot>元素上 -
assignedNodes()默认不展开嵌套结构,必须传{ flatten: true }才能拿到最终投射的所有节点(含 fallback 里的) -
assignedElements()只返回元素节点,适合过滤掉文本节点 - 在
connectedCallback里立刻调assignedNodes(),大概率拿到空数组——内容分发尚未完成
最易被忽略的点是:**slot 的 fallback 内容(即 <slot>...</slot> 里的 HTML)仅在 assignedNodes() 返回空数组时才显示;哪怕只有一个空格文本节点,fallback 就不会出现。** 调试时务必查 API 返回值,而不是肉眼判断。



















