rowspan 必须动态计算而非硬编码,因依赖后续行内容是否变化;正确做法是 JS 从 tbody 首行遍历 td,向下比对 textContent.trim() 直至内容变更,设 rowspan 并跳过已合并行;thead 与 tbody 需分逻辑处理,且需在 DOM 渲染后执行。

rowspan 计算必须从上到下逐行扫描
手动写 rowspan 容易出错,根本原因是:它依赖“后续多少行该单元格内容不变”这个动态判断。一旦某行插入新数据、排序打乱或异步加载,硬编码的 rowspan="3" 就会立刻错位——合并区域覆盖错误单元格,甚至导致表格结构塌陷。
正确做法是用 JS 从 很多人把 原生浏览器对 框架的响应式系统并不跟踪 rowspan 不是视觉糖衣,它是 HTML 表格语义的刚性表达。真正难的不是算出数字,而是让这个数字在数据流、渲染周期、交互事件和辅助技术之间始终保持一致。稍有松动,屏幕阅读器读错、Excel 粘贴失真、拖拽选区漏项,问题就会从 UI 层穿透到数据层。 第一行开始遍历,对每个 向下比对相同文本(注意:要忽略空格、换行、前后空白),直到内容变化为止,再设置 rowspan 值并跳过已合并的行。
rowspan 的单元格,否则重复计算会叠加错误textContent.trim() 而非 innerHTML,避免 HTML 标签干扰表头与 tbody 的 rowspan 处理要分两套逻辑
和 混在一起扫描,结果表头跨行错乱。实际上:
的 rowspan 是为支撑多级表头设计的,而 的 rowspan 是为语义聚合服务的,二者目的不同、计算起点不同、容错要求也不同。 中的 rowspan 应基于列结构定义,通常静态配置,不建议自动推导 中的 rowspan 才需要动态识别,且必须在 DOM 渲染后执行(比如 Vue 的 nextTick 或 jQuery 的 $(document).ready())colspan, 的列索引会偏移,此时不能直接用
cellIndex,得靠 querySelectorAll('tr:first-child td, tr:first-child th') 重新映射列号合并后拖拽选区或复制粘贴会出问题
rowspan 单元格的鼠标事件和剪贴板行为支持不一致。例如:拖拽选中一个跨 3 行的单元格,window.getSelection() 可能只返回首行文本;复制时 Excel 只粘贴一次值,而非填充三行。mousedown/mousemove 逻辑,用 getBoundingClientRect() 算真实像素范围,再反查哪些 被覆盖 copy 事件,手动构造 text/plain 和 text/html 两种格式内容,对 rowspan 单元格做“展开式”填充(即复制成 n 行重复值)rowspan 单元格的 offsetHeight 返回异常,检测时应 fallback 到 clientHeight * rowspan
Vue/React 中直接改 DOM 的 rowspan 属于危险操作
rowspan 属性变化。你在 mounted 里手动设了 td.setAttribute('rowspan', '4'),后续数据更新时,框架可能重绘整行,把你的 rowspan 直接抹掉。
v-for 渲染前就完成 rowspan 数值计算,作为 data 字段传入模板,用 :attr="{ rowspan: item.rowspan }" 绑定useEffect 中执行合并逻辑,并用 ref 拿到真实 DOM 再操作,且每次依赖项变化时先清除旧 rowspan
render 函数里直接操作 DOM——那会导致 reconciliation 失败和样式闪烁
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











