<template> 标签仅是离线容器,轻量级组件引擎本质是JS封装克隆、填充、挂载流程;必须用document.importNode(tmpl.content, true)安全克隆,保留表单状态并兼容Shadow DOM。
<template> 标签本身不是组件引擎,它只是个离线容器;所谓“轻量级组件引擎”,本质是用 JS 封装一套克隆、填充、挂载的固定流程,而不是靠浏览器自动干活。
常见错误是把 <template> 当成普通 HTML 片段去操作。但 template.innerHTML 永远为空字符串,浏览器根本不解析其内容——所有子节点实际藏在 template.content 这个 DocumentFragment 里。
cloneNode(true) 复制后插入,<input checked> 的选中态、<select> 的当前选项、textarea 的光标位置全丢失innerHTML 会销毁已绑定的事件监听器(比如模板里写了个 <button onclick="doSomething()">,克隆后 onclick 不生效).value 或 .checked 设置,不能靠 textContent 或 innerHTML
它能保留表单状态、正确处理 <select> 选项、兼容 Shadow DOM 场景,是现代 DOM 操作的底线要求。
const tmpl = document.getElementById('card-template')
const fragment = document.importNode(tmpl.content, true)(第二个参数 true 必须传)fragment.querySelectorAll('[data-bind]'),按 data-bind="title" 定位节点node.textContent = data.title,表单用 node.value = data.inputValue,富文本需先转义再塞 innerHTML
container.appendChild(fragment),别用 innerHTML += 覆盖已有结构纯 <template> 没有属性监听或生命周期,所谓“传参”就是调用函数时传入一个对象,JS 手动映射到 DOM 节点。
立即学习“前端免费学习笔记(深入)”;
id="card-1",会导致多次渲染时 ID 冲突,破坏 CSS 或 JS 查询逻辑data-bind 属性替代 class 名,比如 data-bind="author-name" 比 class="author" 更易维护、不易被样式覆盖误伤DocumentFragment),而非字符串,避免重复解析textContent 或 dataset 值,不重新克隆这是最容易踩的坑:把 Web Components 的逻辑套到原生 <template> 上,结果什么也不发生,还不报错。
<slot> 只在挂载到 Shadow DOM 时才生效;普通 DOM 中写 <slot name="header"></slot> 等于白写onclick、oninput 在克隆后不会自动绑定,得手动加 addEventListener
<script> 或 <style> 在 cloneNode 或 importNode 后不会执行或生效,别指望它自动加载data-slot 并 appendChild,没有语法糖可省真正难的不是克隆,而是怎么让每次填充都保持状态一致、不污染全局、不触发重排;多数人卡在“以为模板能自己活过来”,其实它连呼吸都要你手动捏人工呼吸器。