必须显式写出空<tbody>标签,否则浏览器自动补全位置不一致导致JS找不到动态行容器;所有含动态数据的表格都应如此,并仅操作<tbody>进行渲染。

为什么直接 innerHTML 拼接表格会丢行
浏览器对缺失 <tbody> 的表格会自动补全,但补全位置不一致——Chrome 可能插在 <thead> 后,Firefox 可能插在末尾。结果就是 document.querySelector('tbody').children.length 在某些情况下返回 0,JS 找不到动态行容器。
- 所有含动态数据的表格,必须显式写出空
<tbody>标签 - JS 渲染只操作
<tbody>,用append()或innerHTML插入<tr>,别碰<thead>和<tfoot> - 避免用
document.write()或直接改<table>.innerHTML,否则已展开的详情行、输入框焦点全丢
template 克隆比字符串拼接更稳
用模板字符串拼 <tr><td>${data.name}</td></tr> 看似简单,但容易 XSS(尤其 data 来自用户输入),也难绑定事件;逐个 document.createElement 又太啰嗦。
- 把单行结构预定义在
<template id="row-template">里,带 class 不带内联样式 - JS 中用
document.getElementById('row-template').content.cloneNode(true)克隆,再填值、插入<tbody> - 批量插入时用
DocumentFragment,避免反复触发重排
数据管道输出必须匹配模板字段名
后端 ETL 流程(比如用 Python + BeautifulSoup 提取、Pandas 清洗、API 输出)如果字段名和前端模板不一致,v-html 或 template 渲染就会留空或报错,但控制台通常不提示。
- 检查 API 返回 JSON 的 key 名是否与模板中引用的完全一致(大小写、下划线/驼峰)
- 字段为空时,后端应返回
null或空字符串,而非缺失该 key,否则data.user.name会报Cannot read property 'name' of undefined - 布尔字段如
is_active,模板里不能写checked="{{ is_active }}",而要用条件逻辑:有该属性即选中,没则不出现
Vue 里 v-html 不等于“放心渲染”
v-html 会直接解析字符串为 DOM,绕过 Vue 的响应式系统和转义机制。哪怕数据来自可信后端,中间若经过日志、缓存、代理层被篡改,就可能执行脚本。
立即学习“前端免费学习笔记(深入)”;
- 仅对明确可控的富文本字段(如 CMS 后台编辑的公告内容)用
v-html - 其他场景优先用插值
{{ }}+textContent,或引入DOMPurify.sanitize()过滤后再v-html - 千万别把用户提交的表单字段、URL 参数、文件名直接塞进
v-html,哪怕加了后端校验
<tbody> 缺失导致 JS 查不到行、v-html 被当成万能解药滥用。这些地方一出问题,现象是“数据明明传过来了,页面就是不显示”,查起来却要倒推三层。



















