不是组件,而是只读dom片段,需手动克隆、填充、挂载;clonenode(true)必须用于重复使用,importnode适用于shadow dom保活态,data-bind解耦绑定,禁用id避免冲突,需桥接到自定义元素直系子节点。

<template></template> 不是组件,它只是个“待克隆的 DOM 片段”——想让它变成真实可用的节点,必须手动克隆、填充、挂载。跳过这三步,页面永远空白。
为什么 cloneNode(true) 是必须的,而不是直接 appendChild(tmpl.content)
tmpl.content 是只读的 DocumentFragment,只能被移动一次。第一次 appendChild(tmpl.content) 后,tmpl.content 就变空了;第二次再调用会静默失败,容器里什么也不出现。
- ✅ 正确做法:每次都要
tmpl.content.cloneNode(true),得到可重复使用的副本 - ❌ 错误写法:
container.appendChild(tmpl.content)(仅能成功一次) - ⚠️ 注意:
cloneNode(true)不会触发<script></script>执行,也不会加载<img>,这是预期行为,不是 bug
data-bind 替代 class 名做绑定点,避免样式与逻辑耦合
用 class="title" 定位节点,一旦设计师改名或加 BEM 前缀,JS 就失效;而 data-bind="title" 是语义化绑定契约,与样式无关,维护成本低。
- 模板中写:
<h2 data-bind="title"></h2> <p data-bind="desc"></p> - 填充时遍历:
fragment.querySelectorAll('[data-bind]'),按属性值映射数据 - 禁止在模板里写
id="card-1"—— 多次实例化会导致 ID 重复,破坏document.getElementById和 CSS 选择器
Shadow DOM 场景下必须用 importNode,不能用 cloneNode
当把模板内容注入 shadowRoot 时,cloneNode(true) 会丢失表单控件状态(比如 <input checked> 的选中态),且无法正确处理 <select></select> 的当前选项。
- ✅ 应该用:
document.importNode(tmpl.content, true) - ❌
cloneNode(true)在 Shadow DOM 中不保活态,尤其影响 checkbox/radio/select -
importNode还能跨文档边界安全复制,适合微前端或 iframe 沙箱环境
slot 在 template 里写无效,必须桥接到自定义元素
直接写 <template><slot name="header"></slot></template> 不会触发任何分发逻辑——<slot></slot> 只在 Shadow DOM 中对自定义元素的**直系子节点**生效,且依赖 JS 显式桥接。
- 有效路径:定义
<template id="card-tpl"></template>→ 创建类继承HTMLElement→this.attachShadow({ mode: 'open' })→shadowRoot.appendChild(tmpl.content.cloneNode(true)) - 使用时必须是直系子节点:
<my-card><h2 slot="header">Title</h2></my-card> - slot 名区分大小写,
slot="Header"和slot="header"不匹配
最易被忽略的是:模板内容默认不执行脚本、不加载资源、不响应属性变更——它不是 Vue 或 React 组件,没有响应式系统。所谓“高效”,指的是 DOM 复用和结构复用,不是自动更新。每次数据变,你得自己决定是重新克隆,还是只更新文本节点。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











