飞鱼视界

东方飞鱼的后花园

个性签名:不敢冒险才是最大的冒险。

Element UI实现表格列宽随内容自适应

发布时间:2021-4-7 作者:Admin 所属分类:

前言

对于动态获取数据的表格,如果期望单元格内容不折行,就要设定足够的宽度,同时又希望表格内容尽量紧凑,但是,由于数据不确定,所以无法预设宽度,怎么办呢?有这样一种办法:

方案

  1. 先让表格渲染
  2. 引入CSS class来让单元格内容单行显示
  3. 遍历表体的.cell,算出每个元素的scrollWidth,汇总到二维数组里
  4. 考察二维数组的每个一级元素的每个单元格的宽度,找出最大值
  5. <el-table-column>设置的width都等于各自列的最大值即可

这个方案按理说,会发生表格闪烁,因为先渲染,又调整列宽的缘故。为了解决这个问题,我想到了visibility: hidden;,当hidden时,表格依然会渲染,只不过不显示,此时就可以计算各种宽度,等计算好,赋值好,再visible即可。

恰好可以借用loading变量实现hiddenvisible的切换。

template

  1. 给表格组件加上这个:
ref="listTable" class="columns-fit" :class="loading ? null : 'visible'" 
  1. 给每个<el-table-column>加上width,如下:
 <el-table-column type="selection" align="center" :width="colWidthList[0]" /> <el-table-column label="序号" align="center" prop="id" :width="colWidthList[1]" /> ... ... 

其中下标表示第几个列。你可以给有些列不设width,或者设置固定数值,此时其他列的下标无需调整,但是如果列顺序变了,下标必须重排。

style

在某个全局引入的scss文件写入:

.columns-fit { .el-table__header-wrapper, .el-table__body-wrapper { visibility: hidden; } &.visible { .el-table__header-wrapper, .el-table__body-wrapper { visibility: visible; } } .el-table__body-wrapper { overflow: auto; } td>.cell { display: inline-block; white-space: nowrap; width: auto; overflow: auto; } } 

script

先不说本方案,先说原始的请求数据列表的代码大致是这样:

 getList() { this.loading = true; list(this.queryParams).then(response => { this.list = response.data; this.total = response.total; this.loading = false; }); }, 

然后我们对它略改造,加上一句:

 getList() { this.loading = true; list(this.queryParams).then(response => { this.list = response.data; this.total = response.total; this.$nextTick(() => { setTimeout(() => { this.colWidthList = this.$adjustColumnWidth(this.$refs['listTable'].$el); this.loading = false; }); }); }); }, 

colWidthListdata里定义一个空数组,用来存每个col的最终宽度。

比较迷的是setTimeout,你是不是不知道我为啥加一句这个?当表格没有横向滚动条,用下方的代码计算出来的每个单元格的scrollWidth会有错误,原因是Element UI的某些计算规则比较迷,它先计算一遍,然后微调一遍,会让单元格稍微变化几像素,而setTimeout从JS底层说是宏任务,可以等待Element UI对单元格的调整结束,这样,得到的scrollWidth才是准的。

adjustColumnWidth函数需要写入一个全局JS:

export default function(el) { let widthList = []; el.querySelectorAll('.el-table__body tr').forEach((tr) => { tr.querySelectorAll('td').forEach((td, i) => { if (!widthList[i]) { widthList[i] = []; } widthList[i].push(td.scrollWidth); }); }); return widthList.map(width => Math.max(...width)); } 

main.js里引入:

import adjustColumnWidth from '@/utils/adjustColumnWidth'; Vue.prototype.$adjustColumnWidth = adjustColumnWidth; 

到此OK。

使用特别说明

1. 本方案不考虑表头的单元格溢出,请另外考虑

image.png

Element UI里面有这样的样式,其中由于text-overflow的值没有none,也就是说,text-overflow一旦写上了就无法取消,导致表头无法像表身一样呈现单行且无省略号的状态,因此也就无法取得我们想要的表头单元格的scrollWidth,所以,本方案不计算表头单元格的宽度。这就导致了一个问题:

如果某列的表头字符很长,但表身内容很短,这样计算得到的width会比表头字符还要短,表头会出现折行。

结论:要么,你就接受这种折行的设定,要么,就给col写死固定的、足够的width值。

2. 删除列、调整列顺序时,:width="colWidthList[n]"的下标要记得对应修改

请记得对应修改。下标应该永远是列的排序序号。

3. 浏览器窗口由小窗拉大到大窗,表格宽度不变,右侧出现空白,怎么解决?

首先说,width属性是Element UI官方属性,如果全部列都设置了width,那么官方也没有办法让表格自适应容器宽度,所以这其实并不是本方案的锅。

我这里提个解决方案:

监听window.onsize,动态修改colWidthList,等比放大,代码我就不写了,因为本身这个需求就是极小概率出现的需求。

4. 不要给所有表格都用本方案

如果表格明显内容稀松,就坚决不要使用本方案,因为没必要。

5. 不要给所有列都用本方案

假如某列的内容忽长忽短,短的只有几个字,长的有50个字,那么这一列显然不适合使用自适应列宽,因为会造成大面积的空白,请给该列锁定width

6. 本方案的缺点

本方案为了不让表格抖动,造成了2个负面效果:

  1. 会让表格消失几十到几百毫秒甚至几秒,根据ajax请求速度而定。如果不采用本方案,表格只是被loading遮罩遮住几十到几百毫秒至几秒,而且遮罩往往半透明,能看到表格的隐约内容,是一种具有“高级感”的设计。

  2. 设置width会导致大规模的UI回流和重绘,页面会非常轻微、不易觉察的卡顿一下,不过好在Element UI做政企系统多,可以强迫用户使用现代浏览器,所以问题很轻微。

总之,如果需求方对界面美观比较在意,对轻微的、不易察觉的卡顿不太在乎,那么可以考虑本方案,如果追求极致流畅,则请不要使用本方案。


作者:microkof
链接:https://www.jianshu.com/p/25bcf9377f88
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

上一篇:element-ui 表格选中行改变行颜色

下一篇:安装electron失败 postinstall: `node install.js`

发表评论: