slot标签仅在Shadow DOM中生效,必须通过自定义元素attachShadow后插入含slot的模板,且name与slot属性需精确匹配、内容须为直系子节点,时机上需监听slotchange事件获取assignedNodes。

slot 标签写在 Light DOM 里完全无效
浏览器会把没挂 Shadow DOM 的 <slot> 当成普通标签忽略,不报错、不警告、也不渲染。常见错误是直接在页面中写:<div><slot name="header"></slot></div>,或者塞进 <div> 里当子元素用——这种写法永远不生效。
必须先注册合法自定义元素,再在 constructor 或 connectedCallback 中调用 this.attachShadow({ mode: 'open' });之后把含 <slot> 的模板(比如 <template>)显式插入到 this.shadowRoot 中。
- 不能对
<div>、<p>等原生元素调用attachShadow(),否则抛出DOMException: This element does not support shadow roots -
{ mode: 'closed' }虽能渲染,但 JS 无法通过this.shadowRoot.querySelector('slot')访问节点,调试时容易误判为“没生效” - 模板插入必须显式执行:
this.shadowRoot.appendChild(template.content.cloneNode(true)),光写<template>标签不等于自动加载
具名插槽 name 和 slot 属性必须严格字符串匹配
<slot name="header"> 只接收 <h2 slot="header">,哪怕多一个空格、大小写错一位、或拼成 slot="Header" 都不匹配。这不是模糊查找,是精确比对。
外部内容还必须是自定义元素的**直系子节点**:<my-card><h2 slot="header">标题</h2></my-card> ✅;<my-card><div><h2 slot="header">标题</h2></div></my-card> ❌ —— <h2> 是孙节点,被直接丢弃。
立即学习“前端免费学习笔记(深入)”;
- 没带
slot属性的元素(如<p>正文</p>)只尝试填入第一个无name的<slot>,后面再多空<slot>也收不到 - 多个同名
<slot name="item">时,每个slot="item"元素按顺序填入一个 slot,不是广播复制 -
<slot><p>缺省文案</p></slot>的 fallback 仅在**完全没有节点分配进来**时显示;哪怕只有一个空文本节点,fallback 就不会出现
查 assignedNodes() 返回空?别急着改代码,先等 slotchange
在 connectedCallback 里立刻调 slot.assignedNodes(),大概率拿到空数组——因为此时 Light DOM 内容还没完成分发。这是最常被忽略的时机问题。
可靠做法是监听 slotchange 事件:slot.addEventListener('slotchange', () => { console.log(slot.assignedNodes({ flatten: true })); })。注意:slotchange 不冒泡、不捕获,也不能在 shadowRoot 上监听,必须绑定到具体 <slot> 元素上。
-
assignedNodes()默认不展开嵌套结构,要拿到所有最终投射进来的节点(包括 fallback 里的),必须加{ flatten: true } -
assignedElements()只返回元素节点,适合需要过滤纯文本的场景 - 这些方法返回的是实时快照,不是响应式引用;DOM 变更后需重新调用
::slotted() 样式穿透只支持单层选择器
::slotted(*) 能样式化投射进来的内容,但它只作用于直接子元素,不支持后代选择器。比如 ::slotted(.header h2) 无效,::slotted(.header) > h2 也无效。
想控制深层结构,得靠 CSS 自定义属性穿透,或在 Light DOM 里预设好类名,再由 Shadow DOM 外部统一管理样式逻辑。
- 投射本质是“投影”,不是 DOM 移动:内容始终保留在 Light DOM 中,
::slotted()只是给它加样式层 - 事件冒泡路径走的是 Light DOM,监听点击得在 Light DOM 节点上绑,不能只查
shadowRoot - HTML 原生
<slot>不支持作用域插槽,也不传递数据;它只做一件事:按规则把 Light DOM 节点投射到占位位置



















