template.content.clonenode(true)是唯一安全的克隆方式:因template内容为只读documentfragment,直接innerhtml拼接易致xss,appendchild(template.content)会搬空模板导致二次调用为空;克隆后需重设id、手动绑定事件、用textcontent/setattribute填充数据。

template.content.cloneNode(true) 是唯一安全的克隆方式
直接 innerHTML 拼接或 appendChild(template.content) 会出问题:前者易 XSS,后者导致模板被“搬空”,第二次调用时 template.content 为空。浏览器把 <template></template> 内容存为只读 DocumentFragment,必须通过 template.content.cloneNode(true) 获取可操作副本。
- 克隆后节点是干净、独立的 DOM 实例——样式未生效、脚本未执行、图片未加载,但结构完整
- 若含
id属性,必须重设(如el.id = 'card-' + Date.now()),否则多个实例 ID 冲突,document.getElementById()行为不可预测 - 克隆节点默认不带事件监听器,需插入后手动绑定,或封装进工厂函数统一处理
填充数据必须用语义化 API,不是 innerHTML
模板里放的是结构,不是字符串容器。用户输入、API 返回的文本内容一律走 textContent;属性变更(如 src、href、data-*)用 setAttribute();表单控件初始值不能靠写死 value="xxx",得显式赋值 el.value = userData.phone。
-
textContent自动转义 HTML 字符,防注入;innerHTML只在你明确需要渲染可信 HTML 片段时才用 - 含
<label for="email"></label>的表单,克隆后要同步更新for和对应<input id="email">的id,否则点击 label 不聚焦 - 用
dataset存上下文标识(如card.dataset.userId = '123'),比塞隐藏字段更轻量、更语义化
template 标签位置不能嵌套
<template></template> 必须作为顶层元素存在,不能包在 <div>、<code><section></section> 或其他组件内部。一旦被包裹,Safari 15.4 之前版本会丢弃其 content,导致克隆后什么都没有。
- 错误写法:
<div class="page"><template id="nav"></template></div> - 正确写法:
<template id="nav">...</template>放在外层,或紧贴开头/结尾 - 如果用构建工具(如 Eleventy、Hugo),
<template></template>不参与最终 HTML 输出,仅作 JS 运行时使用;静态 include 则无需担心此限制
v-for 适合 Vue 场景,但别省略 :key
在 Vue 中批量生成重复结构,v-for 是标准解法,但常见翻车点是忽略 :key。没它,Vue 无法高效追踪节点身份,动态排序或增删时容易渲染错乱。
- 语法必须是
v-for="(item, index) in items" :key="index"或更好用唯一字段::key="item.id" -
v-for不是纯 HTML 机制,依赖 Vue runtime,服务端直出或无 JS 环境下不生效 - 若混用原生
<template></template>和v-for,注意 Vue 会接管模板内容,template.content不再可用











