原生 <template> 标签不解析模板语法,{{title}} 等占位符仅作字符串显示;可读性依赖 HTML 结构、语义化 class 命名与缩进规范,JS 需手动填充内容、绑定事件并同步状态。

原生 <template> 标签本身不解析、不渲染、不响应数据,所谓“声明式”只是结构层面的语义表达,真正的可读性来自 HTML 结构设计 + class 命名 + 缩进规范,而非模板语法能力。
为什么直接写 {{title}} 在 <template> 里毫无作用
浏览器把 <template> 当作纯文本仓库,content 是只读的 DocumentFragment。你写的 {{title}} 就是字面量字符串,不会被替换;v-if 或 ngIf 更是完全无效——它们依赖框架运行时解析,原生 HTML 不认识这些指令。
- 常见错误:把 Vue 模板复制进
<template id="card">,结果克隆后页面显示{{title}}文本,控制台无报错,只有空白或乱码 - 真正起效的是 JS 层手动操作:
clone.querySelector('.card-title').textContent = config.title - 想保留“声明感”,只能靠 class 名和 DOM 路径清晰表达意图,比如
.card-title、.card-avatar、.card-cta,而不是靠占位符
<template> 内部 HTML 的可读性怎么保障
没有框架兜底时,“可读性强”取决于三件事:缩进是否一致、class 是否语义化、结构是否自闭合且无歧义。
- 所有子元素独占一行,嵌套层级用 2 或 4 空格缩进(不要用 Tab)
- 禁用泛化 class:
.header、.box、.item—— 改用带命名空间的语义名:.c-card__title、.c-card__avatar、.c-card__actions - 避免
<div class="card">这种结构,它无法隔离样式作用域;应写成完整自包含块:<div class="c-card"><div class="c-card__body">...</div></div> - 关键容器结束处加注释:
<!-- .c-card -->,尤其在多层嵌套或含<slot>时
如何让配置项与模板节点一一对应
可读性最终体现在 JS 渲染逻辑能否“望文知意”。配置字段名、class 名、DOM 查询路径必须对齐,否则一改就断。
将调研报告、方案对比、数据分析、需求梳理、会议纪要、设计说明、代码评审、学习笔记等任务产物输出为可在浏览器直接打开的单文件 HTML,替代 Markdown 作为最终交付物。Markdown 在信息密度、视觉清晰度和可分享性上已跟不上 AI 产物的丰富度,HTML 能同时承载排版、表格、SVG 等。
立即学习“前端免费学习笔记(深入)”;
- 配置对象字段用驼峰或 kebab-case,与 class 名映射:如
config.ctaText→.c-card__cta,config.avatarUrl→.c-card__avatar - 所有用户可控内容(如描述、标题)统一走
textContent,防 XSS;图片src做协议校验:if (!/^https?:\/\//.test(url) && !/^data:/.test(url) && !/^\//.test(url)) return '' - 交互元素(按钮、开关)每次克隆后必须重新绑定事件:
clone.querySelector('.c-card__cta').addEventListener('click', handler),不能依赖事件委托——在 Shadow DOM 或多次插入场景下会失效
组件更新时模板重用的陷阱
<template> 只提供结构副本,不维护状态。所谓“更新”,其实是清空旧节点、克隆新副本、填值、绑事件、再插入——这个过程容易漏掉某一步。
- 不要在
connectedCallback里异步 fetch 配置然后直接 render,首次可能渲染空结构 - 推荐做法:配置就绪后调用
this.render(config),内部执行:this.container.innerHTML = ''→const clone = template.content.cloneNode(true)→ 填值 → 绑事件 →this.container.appendChild(clone) - 特别注意:
cloneNode(true)不复制已绑定的事件监听器,也不恢复 input 的 value 或 checkbox 的 checked 状态——这些必须手动同步
最容易被忽略的点:template 不是活的,它不保存任何状态;所谓“可配置”,全靠 JS 对克隆节点的精准操作。可读性不是写得像 Vue,而是让每个 querySelector 调用都像读一句自然语言——.c-card__title 就该只负责标题,.c-card__avatar 就该只管头像,不多不少,不隐不藏。


















