文章目录
- 前言
- 一、目标效果
- 二、失败方案
- 三、正确方案
- 四、解决正确方案中的一个Bug
- 总结
前言
前端表格分页.
带纵向合并的表格, 到达固定行数强制分页, 截断本页纵向合并, 在下页展示该纵向列的剩余部分, 代码多为前端数据处理, 所以仅提供思路.
这并不难, 你可以直接看第三节.
一、目标效果
未分页状态:
红线以上为表头, 这看起来似乎不复杂, 主要问题是需要分页, 而且是以右侧的那种小行为单位, 43行为一页, 而左侧 id colspan
并不固定, 没有人知道这次请求的数据会有几个在这一栏.
分页状态:
如果左侧长栏受到分页切割, 那么应该在两页均显示这一栏, 就像这样:
二、失败方案
起初的方案先依据id
属性对包含所有数据的大数组做切分, 先把分段做出来, 计算每段的小计加入段末, 之后根据段数组长定制每段id
的colspan
进而得到tag
的colspan
, 将colspan
作为一个特殊的属性(我用的是idColspan
)添加给每个段数组的第一个元素, 即加给每段第一行的行数据对象.
之后将标记了段首colspan
并增加了段尾小计行的所有分段数据拆解, 重新组合为一个大数组, 分页后直接v-for
遍历生成每页, 遍历时v-if
, 若该行存在标记了colspan
的特殊属性或者标记了小计行的特殊属性, 那么单独使用一种渲染方案:
<tr> <!-- 每段作为一个tr -->
<template v-for="(row, rowIndex) in tableData">
<td v-if="row.xj" :key></td> <!-- 小计行渲染方案 -->
<td v-else-if="row.idColspan" :key :colspan="idColspan"></td> <!-- id行渲染方案 -->
<td v-else :key></td>
</template>
</tr>
这套方案不分页是没有任何问题的…
渲染起来倒也很方便, 直到做完这一套…分页之后彻底崩了.
如果长侧栏被切, 第二页起头就会因为缺少id
和tag
格而错乱.
三、正确方案
主要区别就是在分页之后才进行了分段, 而非先分段再分页.
段肯定是要分的, 因为小计行需要在前端计算并且加到数据里, 段长固定还好, 段长不固定情况下不分段直接算有点难规划.
每一条数据有一个saName
属性, 所有saName
属性相同的数据在数组中都相邻并成段分布.
应该对每一行对象都加上它们所属的id
, 比如第8行对应的id
为2, 那么第八行的id
属性值为2, tag
也是, 每行都加, 一定要在这里加, 不要分页之后, 不然每页你id
都从1开始…
然后在数据的段形态下计算并加小计行到正确位置, 这个不说了, 但是一定要在分页前把小计算好加进去.
加完之后还是拆, 把所有加了小计行的段数组合并成一个大数组, 依据pageSize
进行分页.
分页之后, 在每页的基础上计算id
和tag
的colspan
, 就不用担心分页后长栏被切了.
然后开始做每页的长栏, 提取这页的所有id
值种类(比如这是第三页, id
只有4, 5, 6这三种), 你必须提取而不是直接用刚开始的那个包含所有id
种类的数组, 那会报undefined
,
可以用以下:
const idArr = Array.from(new Set(xxx.map(item => item.id)))
然后依据id
种类数组将本页的这些总数据进行分段, 根据段数组长度来判定id
的colspan
值, 作为一个特殊属性(比如我写的那个idColspan
)加给每段的第一个行数据对象, 这样渲染的时候还是老套路直接一个template
里面三种方案, 根据当前受遍历行具备何种特殊属性来判定合适的渲染方案.
四、解决正确方案中的一个Bug
这种方案看着很完美, 但是还有一个小Bug, 因为tag
的colspan
是比id
的colspan
小1的, 要给小计行腾一个colspan
出来, 所以我想你可能会向我一样直接减了一个1就赋值了, 然后你就发现…
如果这一页的末尾对一个段进行了切割, 也就是这一页的最后一行不是小计行, 那么最后一行是不正确的, 一个正常的数据行会占据原本小计的位置.
解决方法也很简单, 我们对当页数据分段的时候不是设置了tag
的colspan
吗? 判定一下, 如果当前段的最后一行不是小计行, 即不具备"xj
"属性, 那么我们不需要给小计行留空位, 令tag
的colspan
等于id
的colspan
即可完美实现.
总结
如果它帮到你, 我很高兴.