模板通过调用方显式传入纯对象参数获取数据,如rendercard({ title: '订单详情', items: [...] }),禁止模板内嵌fetch或localstorage等副作用逻辑,数据获取与错误处理均由上层负责。

模板怎么拿到数据?别硬塞,走明确的数据入口
HTML模板本身不主动拉数据,它只等被喂——所有数据必须由调用方显式传入。常见错误是把 fetch 或 localStorage.getItem 塞进模板函数里,结果导致模板无法复用、测试困难、副作用不可控。
正确做法是让模板函数只接收纯对象参数,比如:renderCard({ title: '订单详情', items: [...] })。数据获取、错误处理、加载状态都交给上层逻辑,模板只负责“画”。
- 模板函数不应包含异步操作,也不该直接读取
window.location或document.cookie - 若需默认值,应在调用前合并:
const data = { ...defaults, ...userInput },而非在模板内写{{ title || '暂无标题' }} - 对数组类数据,提前做空值判断(
items?.length > 0),避免模板里出现Cannot read property 'map' of undefined
组件匹配靠什么?不是 class 名,是 data-bind 属性
用 class="card-title" 绑定内容,等于把样式和逻辑耦合死。一旦改 CSS 类名,JS 就崩;多人协作时更易冲突。真正可维护的匹配方式是用语义化 data-bind 属性。
例如模板中写:<h3 data-bind="title"></h3>,JS 里统一用 fragment.querySelectorAll('[data-bind]') 扫描并填充。这样样式可换、结构可调,绑定关系不变。
- 禁止用
id做绑定点——重复渲染时 ID 冲突,document.getElementById只返回第一个 -
data-bind="user.name"这种嵌套路径不推荐,解析成本高且易出错;扁平化数据结构更稳妥 - 表单控件(
input、select)必须用value或checked属性赋值,不能只改textContent
数据流向卡在哪?DOM 更新不触发重绘的三个典型场景
模板渲染完,数据变了但页面没更新,往往不是模板问题,而是 DOM 操作方式踩了浏览器渲染机制的坑。
最常踩的三个点:innerHTML 覆盖整个容器会销毁已有节点状态(比如 input 的光标位置、video 的播放进度);直接修改 textContent 不会触发 CSS 动画重播;用 cloneNode(true) 复制含 script 的模板,脚本不会执行。
- 优先用
document.importNode(tmpl.content, true)替代cloneNode,它能保留表单状态和 Shadow DOM 兼容性 - 需要局部更新时,只替换目标节点内容,不要整块
innerHTML = ... - 若模板含内联
<script></script>,得手动遍历执行:fragment.querySelectorAll('script').forEach(s => eval(s.textContent))(仅限可信环境)
为什么不用框架也要关心响应式?模板结构决定适配上限
一个 HTML 模板是否支持响应式,不取决于你写了多少媒体查询,而取决于它的结构是否允许 CSS 独立控制布局流。很多“响应式失败”其实源于模板本身用了固定宽度、硬编码 px、或嵌套过深的 div。
比如写 <div class="c-card" style="width: 300px">,再强的 CSS 也救不回来;而写 <code><div class="c-card"> 配合 <code>max-width: 100% 和 var(--c-space-md),就能随容器缩放。
- 禁用
px单位,所有间距、圆角、字体大小必须基于 CSS 自定义属性(如var(--c-space-lg)) - 避免用
float或position: absolute构建主布局,优先用 Flex/Grid - 模板里不要写
<meta name="viewport">—— 它属于页面级配置,每个模板不该自己决定视口行为











