template元素本身不执行插槽注入,真正支持插槽分发的是shadowroot与自定义元素组合;命名插槽需显式设置slot属性,父级内容会无条件覆盖默认插槽fallback内容。

template 元素本身不执行插槽注入
template 是一个惰性容器,它的 content 属性只提供 DOM 片段,不会自动识别或处理 <slot></slot>。也就是说,直接克隆 template 并 append 到普通 DOM 中,<slot></slot> 标签会原样保留,不会被替换——它不是 Web Components 的 Shadow DOM,也没有内置的插槽分发逻辑。
真正支持插槽分发的,是 ShadowRoot + 自定义元素(customElements.define)组合。只有在 attachShadow 后,浏览器才会解析并执行插槽内容分发规则。
- 错误做法:把含
<slot name="header"></slot>的template克隆后直接插入document.body→ 插槽不生效,只显示空标签 - 正确路径:必须通过自定义元素 +
attachShadow({ mode: 'open' })创建封闭上下文 - 注意:不能在非 Shadow DOM 环境下“模拟”插槽行为,否则要自己遍历、匹配、移动节点——这已脱离 HTML5 插槽语义,属于手动 DOM 操作
命名插槽注入需显式设置 slot 属性
即使在 Shadow DOM 中,父级传入的内容也不会自动落入对应命名插槽,除非该内容节点明确携带 slot="xxx" 属性。
例如,你有:
<template id="card"><div class="card">
<header><slot name="header">默认标题</slot></header><main><slot>默认正文</slot></main>
</div>
</template>
那么使用时必须写:
<card-component><h2 slot="header">我的标题</h2> <p>这是正文内容</p><div class="aritcle_card flexRow artxards"> <div class="artcardd flexRow"> <a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill4293" title="Doc To HTML"><img src="https://img.php.cn/upload/skill/000/000/081/178998486916110.jpg" alt="Doc To HTML" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a> <div class="aritcle_card_info flexColumn"> <a rel="nofollow" href="/xiazai/skill4293" title="Doc To HTML" class="overflowclass">Doc To HTML</a> <p class="overflowclass">使用 MinerU 文档处理引擎将 Word 文档(.doc、.docx)转换为保留结构和格式的干净 HTML。</p> </div> <a rel="nofollow" href="/xiazai/skill4293" title="Doc To HTML" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span> </a> </div> </div> </card-component>
- 漏掉
slot="header"→<h2></h2>会落到默认插槽(即<slot></slot>),而非<slot name="header"></slot> -
slot值区分大小写,且必须与模板中name完全一致 - 多个同名
slot属性的元素会被一起分发到同一个命名插槽中
默认插槽内容会被完全覆盖
当父组件向自定义元素内部写入任何子节点(哪怕只有一个文本节点),只要没加 slot 属性,它们就全部进入默认插槽,并**取代**模板中 <slot></slot> 内的 fallback 内容。
比如模板里写的是:
<slot>加载中...</slot>
而你在页面中这样用:
<card-component>Hello</card-component>
结果只会显示 “Hello”,不会显示 “加载中...”。这个覆盖是无条件的。
- 想保留 fallback,又允许传入内容?只能靠 JavaScript 判断
shadowRoot.querySelector('slot:not([name])').assignedNodes().length === 0,再手动插入 fallback —— 但这就不是纯 HTML 插槽了 - 不要指望
<slot>xxx</slot>在有传入内容时还能作为兜底展示,它只在无传入时生效
动态注入需 cloneNode(true) + 分配前清空旧内容
如果多次实例化同一模板(比如渲染列表项),每次都要确保:
- 调用
template.content.cloneNode(true),而不是复用同一份 fragment(否则节点被移动后第二次 append 会失败) - 在将新内容 append 到 shadowRoot 前,先清空已有内容:
shadowRoot.innerHTML = ''或shadowRoot.replaceChildren() - 若用
innerHTML设置模板 HTML 字符串,<slot></slot>会被当作普通标签解析,失去插槽语义 → 必须用template.content
常见翻车点:在 connectedCallback 里反复 shadowRoot.appendChild(template.content),第二次就会报错 “Failed to execute 'appendChild' on 'Node': This node is already a child of another node.”
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










