ElementUI表格el-table表头固定自适应高度解决方案

来源 | https://wintc.top/article/54

ElementUI、iView都以相同的方式提供了表格组件表头固定的方法,即设置组件的height属性。

表头固定很重要,就在于当表格数据项很多时,滚动条出现在表格组件内,而不是出现在表格组件外——这样的优点在于,滚动浏览数据项时,表头不发生滚动而永远在可视区域,数据项的字段名可以一直看到。

el-table的height属性可以方便地实现表格固定,但是这个值该设置为多少以适配屏幕大小呢?设置过小,则可能出现可视区域内有空白位置,但是表格内却出现滚动条;设置过大,则在一些小屏幕设备上浏览时,页面本身和表格内部都可能会出现滚动条。

两种情况体验都是极差的,为了解决这个问题,我们需要动态地计算页面空白区域的高度,然后设置到height属性,即根据页面大小,动态计算height属性。

这个问题难以抽象出通用的插件来解决,因为表格适合的高度在不同页面都不尽相同。

本文使用的方案是,使用CSS和JS结合的方式,首先使用CSS规划出一个自适应高度的容器container,组件放到container的内部使用absolute绝对定位脱离文档流(如此table的高度不会影响到页面布局),然后使用JS获取container的高度tableHeight,将该值设置为el-table的height属性,从而实现表格自适应高度固定表头。

一、使用CSS规划自适应高度的容器container

这里所谓“自适应”,是指一个元素(往往是内容多少不固定)充分利用页面剩余空间来展示内容。

使用CSS来做适应性布局,就是要减少在代码中出现数值类属性,充分地利用CSS各属性的特性让同一份代码在不同尺寸的设备中都能自由兼容呈现。最常用并且也最简单的一种适应性布局技巧是弹性布局,即flex布局。

下面是一个简单的例子,红色框是父容器,蓝色框是自适应高度的内容区域,该元素没有设置height属性,其高度自动适应为父元素高度减去“头部”的高度、padding、头部和“内容”之间的margin等。

<div class="container">    <div class="header">不确定高度的头部</div>    <div class="content">自适应父元素剩余高度的内容</div></div>

用flex实现非常简单:

.container {  display: flex;    flex-direction: column;}.header { flex-shrink: 0; }.content { flex: auto; }
.container {    height: 300px;    width: 250px;    text-align: center;    border: 1px solid red;    padding: 10px;}
.header {    padding: 20px;    border: 1px solid green;    margin-bottom: 10px;}
.content {    border: 1px solid blue;}

前三条规则就是本例中的核心,对于container,通过display: flex声明它是一个flex盒子,flex-direction: column则表示flex弹性扩展方向是纵向;对于content,flex: auto表示该元素弹性扩张占满父元素剩余空间。

在使用表格呈现数据时,我们可以使用自适应布局的技巧,使得除去页面中的菜单、导航、各类按钮等占据的空间,表格刚好占满页面剩余空间,然后固定表头。以一个常规管理后台布局为例:

其中自适应区域我们用来放表格内容,其余各个部分都是固定的,在不同尺寸的设备中,自适应区域宽高自适应。只需要在CSS中重复使用display: flex设置容器为flex弹性容器、flex:auto使得某一部分占满父元素剩余空间即可。HTML和核心CSS代码如下:

<body>    <div id="app" class="flex-c">        <div class="header flex-s">头部导航</div>        <div class="content flex-a flex">            <div class="left flex-s">左部菜单</div>            <div class="right flex-a flex-c">                <div class="menu-list flex-s">表格菜单</div>                <div class="table-container flex-a" ref="container">自适应区域</div>                <div class="pagination flex-s">表格分页</div>            </div>        </div>    </div></body>
html {  height: 100%;}
body {  height: 100%;  margin: 0;}
#app {  height: 100%;  text-align: center;}
.flex, .flex-c { display: flex }.flex-c { flex-direction: column; }.flex-a { flex: auto; }.flex-s { flex-shrink: 0; }

二、动态计算表格高度

我们把表格插入到自适应区域,并将设置自适应区域为相对定位,表格容器设置为绝对定位:

<div class="table-container flex-a" ref="container">    <div class="table-container-inner">        <el-table        :data="tableData"        :height="tableHeight"        border>        </el-table>    </div></div>
.table-container {    position: relative;}
.table-container-inner {    position: absolute;    left: 0;    right: 0;    top: 0}

然后我们使用Element.getBoundingClientRect()这个接口来获取自适应区域的高度,设置为表格高度,这样即可达到自适应高度固定表头的效果。

export default {  data () {    return {      tableHeight: 0,      tableData: [        // xxx 表格数据      ]    }  },  mounted () {    this.calHeight()  },  methods: {    calHeight () {      this.$nextTick(() => {        const rect = this.$refs.container.getBoundingClientRect()        this.tableHeight = rect.height      })    }  }}

当然,在用户操作的过程中,免不了会有一些影响页面布局的因素,此时我们需要重新计算一次高度。其中最常见的一种操作是改变浏览器窗口的大小,我们可以通过监听resize事件来重新计算高度:

data () {    return {        timer: 0    }}mounted () {    // ...    window.addEventListener('resize', this.onResize)},beforeDestroy () {    this.timer && clearTimeout(this.timer)Z          window.removeEventListener('resize', this.onResize)},methods: {    // ...    onResize () {        this.timer && clearTimeout(this.timer)        this.timer = setTimeout(() => {            this.calHeight()        }, 500)    }}

为了避免resize高频触发回调,这里使用定时器进行一个简单的控制。完整例子可以查看:http://jsrun.net/v56Kp/edit。

三、影响容器高度的其它因素

以上解决方案考虑了窗口resize对表格容器container高度的影响,这是绝大部分需要重新计算表格高度的情况。然而,其它一些情况也可能导致container高度变化,比如DOM增删或者是样式修改引发页面布局变动。

如果想做得更完美,可以在引发这些操作的地方调用calHeight方法,或者使用MutationObserver观察到这些修改。

本文完〜

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值