template 标签不渲染,需 clonenode(true) 克隆使用;slot 仅在 shadow dom 中生效,且只对自定义元素直系子节点分发;必须通过 custom element attachshadow 并插入克隆模板才能实现组件化。

template 标签本身不渲染,必须手动克隆才能用
直接把 <template></template> 写在页面里,它就像一张没打印的图纸——浏览器完全忽略、不解析、不渲染,也不会报错。很多人误以为写进去就能当组件用,结果页面空空如也。
- 必须通过
document.getElementById('xxx').content.cloneNode(true)显式取出并插入 DOM -
cloneNode(true)是关键:浅克隆(false)只复制顶层节点,内部文本和子元素会丢失 - 模板里写的
<slot></slot>在 template 内部无效——它只在 Shadow DOM 中起作用,不是“声明即生效” - 如果模板含内联
<style></style>,克隆后样式仍生效;但若依赖外部 CSS,则需确保目标容器已加载对应类名
slot 只在自定义元素 + Shadow DOM 中分发内容
原生 <slot></slot> 不是“全局插槽”,它只对挂载了 Shadow DOM 的自定义元素的**直系子节点**做内容分发,且严格匹配 slot="name" 属性。
将调研报告、方案对比、数据分析、需求梳理、会议纪要、设计说明、代码评审、学习笔记等任务产物输出为可在浏览器直接打开的单文件 HTML,替代 Markdown 作为最终交付物。Markdown 在信息密度、视觉清晰度和可分享性上已跟不上 AI 产物的丰富度,HTML 能同时承载排版、表格、SVG 等。
- 写
<my-card><h2 slot="title">Hello</h2></my-card>时,<h2></h2>必须是<my-card></my-card>的直接子元素,嵌套一层(如包在<div> 里)就失效 <li>命名插槽大小写敏感:<code>slot="Header"和slot="header"不匹配 - 默认插槽(无 name)接收所有未指定 slot 属性的直系子节点,但多个节点会被一起塞进同一个
<slot></slot>,无法拆分 - 想监听插槽内容变化?得用
slot.addEventListener('slotchange', handler),不是 MutationObserver - 模板定义要带 id:
<template id="modal-tpl"><div><slot name="body"></slot></div></template> - 自定义类里必须调用
this.attachShadow({ mode: 'open' }),否则<slot></slot>不工作 - 插入模板内容用
shadowRoot.appendChild(tpl.content.cloneNode(true)),不能用innerHTML—— 否则<slot></slot>节点不会被识别为分发入口 - 属性传值(如
<my-modal title="确认"></my-modal>)需在attributeChangedCallback中手动同步到 shadow 内部,slot 不处理属性 - 命名插槽名应语义明确:
slot="actions"比slot="btns"更易理解,也方便后续加 ARIA 标识 - 给命名插槽设默认内容需写在
<slot></slot>标签内:<slot name="footer"><button type="button">取消</button></slot> - 不要为每个小区域都设命名插槽——比如卡片里「头像」「用户名」「状态标签」全拆成 slot,反而让使用者记不住顺序和语义
- 若某插槽内容极少变动(如固定「关闭 ×」按钮),直接写死在模板里,比暴露 slot 更稳定
用 Custom Element 桥接 template 和 slot 才算真正可用
单纯用 <template></template> + <slot></slot> 不构成组件;必须注册自定义元素,并在构造函数中 attachShadow + 插入克隆模板。
命名插槽比默认插槽更可控,但别滥用
一个组件超过两个可替换区域时,命名插槽几乎是唯一靠谱的选择;但每个命名插槽都意味着使用者多一个契约约束。










