vue组件-固定表格

Front End 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 顺利跑就问题不大了.

后续会继续优化

放假了, 过年了

祝大家新年快乐 !