vue组件-固定表格
固定表格
后台管理系统,多多少少会有列表页.
而列表页又正是由表格形成.
但是原生的表头并不能固定头部以及两侧.
一旦数据多了,查看起来就不方便了.
于是乎就出现很多固定表头/两侧的表格组件
实现原理
绝对定位
实现方式 这种应该是最普遍也是最简单的方式.
就是将一个表格分成多个表格.
包括表头/左侧/右侧/表体, 共四个表格
然后通过 css 方式将表头以及两侧固定
之后通过 scroll 事件的监听,同步表头以及两侧的 scroll 值,就可以达到固定的效果
优点 实现起来简单,而且无缝滚动
缺点 表格都是使用 table-layout:fixed; 使得每个单元格宽度固定.
如果不使用 fixed 的话.则需要一个
管理每一列的宽度. 这样不能达到宽度自适应的情况
滚动必须是局部滚动.而不是跟随全局.
例子 elementUI 的表格就是这样实现的. 同一个表格的表头,表体分别复制了3次.用来形成表头和两侧的固定.
使用绝对定位固定两侧.
通过管理 scroll 的值管理表头以及两侧滚动.
这样就会导致 dom 数量的增加.
css 方法 - position: sticky
此方法原生支持固定表头.
但是目前兼容性不客观
本文实现
- DEMO(原谅我没弄样式)
背景
当固定表头的需求提出来时,我也是曾经想过直接使用 elementUI 的表格.
但是发现使用 elementUI 的表格插件需要改动不少代码.而且感觉不够灵活.
于是就自己去实现
第一版
由于考虑到不想使用 fixed 布局以及组个单元格去管理宽度.
而且不想使用局部滚动
所以一开始就决定使用 监听全局滚动+transition 方式.让表格头跟随滚动走
也就是说.当表头贴近浏览器上端的时候才固定.
而不是局部滚动式的固定.
这样 thead 和 tbody 就是一体,不存在宽度不一致问题
兼容性问题
一旦thead产生了 transform. 表格的 border-collapse 会失效.表格头的边框会消失.
为了解决这个问题.我使用阴影来替代 border.
但是在 safari 上.transform 部分不会显示出阴影..暂无解
对于 transition 问题.
在 chrome 下不存在闪烁卡顿现象, 而在 Firefox 和 safari 则存在闪烁和卡顿现象.
由于是内部系统, 使用 chrome 居多.所以 firefox 和 safari 下只做了兼容性处理.
第二版
在第一版完成后, 基本实现了固定表格头功能. 而且在 chrome 下表现顺畅.
于是着手实现固定两侧.这里实现原理一样.所以很容易实现
这种虽然右侧是固定在浏览器右侧.
但是整体页面还是被撑开的.
那么对于表格上下的其他组件,他们依旧是被浏览器隐藏.需要横向滚动才能看到.
于是我继续开始第三版改造
第三版
这一版主要就是为了页面的其他组件不被表格的宽高影响.也就是说不管表格多高多宽.
都可以在不滚动的前提下看到.
那么就是将表格变成局部滚动了.
其实就是一个自适应的内滚动容器.
前提是页面高度宽度都是100%
也就是说要有环境让容器产生滚动
监听此容器的滚动来控制表格头和两侧的固定.
但是收到反馈说这种表格看起来很狭小.不够大气
没办法,只能继续进行思考改进
思考改进
在开始之前我的想法是
结合第二第三版.
将垂直滚动交给页面.横向滚动自管理.
什么意思呢?
就是页面高度可以被撑开. 但是宽度不能被撑开.
也就是说全局只有 y 轴滚动.没有 x 轴滚动.
其实第三版是可以实现的.
页面只需限制宽度为100%.高度不做限制,就可以轻松的达到要求.
注意这里的高度其实没有做限制的.也就是说容器滚动条被隐藏了.
那如果要横向滚动怎么办.
很简单啊.按着 shift 再滚动就是横向滚动了.
这是不科学的.不是每个人都知道.
那样是不是可以有一条虚拟的横向滚动条, 来管理表格的横向滚动呢.
于是就有第四版
第四版
就是就是额外添加一个虚拟滚动条的组件.
当容器底部被浏览器隐藏时候.则平移这个滚动条至屏幕底部
- 原生滚动条被隐藏时候,显示虚拟滚动条
- 原生滚动条显示时候,隐藏虚拟滚动条
这样, 既能使得页面不被撑开. 同时高度也不需要限定在100%.
刚好能满足需求.
实现方法
实现方法其实就是使用 transform 以及监听滚动来实现固定咯.
但是在使用上,则需要有一定的规则.
也就是说
在使用的时候.要通过 slot 分别配置 head,left,right 的内容.
简单说就是把表格拆分成左/中/右
那么 thead 和 tbody 就能保持列宽度.
关键处理:
- 通过 slot配置左/中/右以及表格头/表格体
- hover 样式需要通过 mouseOver 和 mouseleave 去管理
- 通过监听表格和窗口的 resize 事件,以及使用 MutationObserver 来监听表格子节点的变化来重新获取表格宽度.(因为双侧固定需要依赖左中右的宽度)
- 通过监听全局滚动, 固定表格头
- 通过监听父容器的横向滚动, 固定两侧
不足之处
兼容性不太好, 在 chrome 表现良好(至少高版本的流畅), firefox 和 safari 则有卡顿现象,目前做法是在滚动时候,使用 opcity 将固定部分隐藏.滚动结束后显示
table 宽度变更时候. 右侧会有闪烁. 因为右侧固定算是很依赖表格宽度以及自身宽度.所以宽度变化对右侧影响很大. 暂未解决
需要有 css 支持. 让容易有一个可滚动的环境.
使用时候会把正常的 table 拆分成几部分.
AlignCell 是什么 ?
其实就是 th 或者 td.
封装起来就是因为设计师想要达到表格每一列整体居中的前提下,左或者右对齐.
当然, 当数据量多的时候,每个单元格基本都是刚满足宽度. 直接左对齐是没问题的.
但是当数据不多.每个单元格宽度都是充足时候,这时候直接使用左对齐是不行的
那么,我也只好封装一层了. 这里就不介绍了
结语
虽然瑕疵比较多.但是开发整个组件过程,我个人是收获不少的.
由于是内部系统.也没怎么考虑兼容性.能在 chrome 顺利跑就问题不大了.
后续会继续优化
放假了, 过年了
祝大家新年快乐 !