slot name属性必须与外部slot="xxx"严格字符串匹配,大小写、空格、连字符均敏感;多个具名slot按顺序分发直系子节点;默认slot仅接收未被具名拦截的第一个匿名子节点;::slotted()仅作用于投射的直系元素本身。

slot name属性必须和外部slot="xxx"严格字符串匹配
大小写、空格、连字符全部敏感,slot="Header"和<slot name="header"></slot>完全不匹配。浏览器不做容错,也不报错,内容直接被丢弃。常见错误是命名用驼峰(slot="mainContent")但组件内写短横线(name="main-content"),结果页面空白。
验证方式很简单:在slotchange回调里打印slot.assignedNodes({ flatten: true }),如果为空,先检查这两处字符串是否逐字一致。
卡片布局中多个具名slot要按顺序接收不同子节点
比如卡片需要标题、副标题、操作按钮三个区域,就得在 Shadow DOM 中写三个具名 <slot name="title"></slot>、<slot name="subtitle"></slot>、<slot name="action"></slot>。外部使用时,每个元素必须带对应 slot 属性,且只能是 <my-card></my-card> 的直系子节点:
- ✅
<my-card><h1 slot="title">订单详情</h1> <p slot="subtitle">2026-08-12</p> <button slot="action">编辑</button></my-card> - ❌
<my-card><div><h1 slot="title">...</h1></div></my-card>(<h1></h1>是孙节点,不参与分发)
注意:同名 <slot name="item"></slot> 写两次,不是复制内容,而是按顺序分发——第一个 <slot></slot> 接收第一个 slot="item" 元素,第二个 <slot></slot> 接收第二个,以此类推。
默认slot只收“没被具名slot拦截”的直系子节点
如果卡片模板里除了 <slot name="title"></slot> 还有一个无 name 的 <slot></slot>,那它只会收到那些没写 slot 属性的子节点,而且只认第一个——后面再加几个匿名 <slot></slot> 都是空的。
例如:<my-card><h1 slot="title">标题</h1>
<p>正文第一段</p>
<p>正文第二段</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill5806" title="html-deploy"><img
src="https://img.php.cn/upload/skill/000/000/081/179066538882434.jpg" alt="html-deploy" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/skill5806" title="html-deploy" class="overflowclass">html-deploy</a>
<p class="overflowclass">使用 htmlcode.fun 将 HTML 内容或文件部署到网页,适用于用户要求“部署到网页”“托管此 HTML”“生成此前端...的实时链接”等场景。</p>
</div>
<a rel="nofollow" href="/xiazai/skill5806" title="html-deploy" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div></my-card>,只有第一个 <p></p> 会进默认 <slot></slot>,第二个 <p></p> 不会被渲染(仍在 Light DOM 中,但不可见)。
想让多段内容都进来?要么全显式指定 slot 名(如 slot="content"),要么只留一个默认 <slot></slot> 并把所有内容包在一层容器里(但注意:这会让它们变成非直系子节点,又失效了——所以正确做法是让用户自己控制结构,组件只提供 slot 占位)。
::slotted()样式只能作用于投射进来的直系子元素
::slotted(h2) 可以给投进 <slot name="title"></slot> 的 <h2></h2> 加样式,但 ::slotted(.btn span) 或 ::slotted(*):hover 全部无效。浏览器强制限制它只匹配被投射节点本身,不穿透后代。
实际能做的有限:
- ✅
::slotted([slot="action"]) { margin-left: auto; } - ✅
::slotted(.primary) { color: var(--primary-color); }(前提是用户自己写了class="primary") - ❌
::slotted(button .icon)——.icon是button的子元素,不在投射层级上
真要控制深层样式,得靠 CSS 自定义属性透传(如组件定义 :host { --btn-padding: 8px; },用户在投射节点里用 padding: var(--btn-padding)),或者监听 slotchange 后手动遍历 assignedNodes({ flatten: true }) 加 class。
最常被忽略的是:slot 分发不是立即完成的。哪怕你把模板写对了、名字配上了、节点也放对位置了,在 connectedCallback 里调 slot.assignedNodes() 依然大概率为空。必须等 slotchange 事件触发后才能拿到真实投射节点,而且记得传 { flatten: true }——否则 fallback 里的内容、嵌套结构都看不到。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










