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

前言

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

方案

  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做政企系统多,可以强迫用户使用现代浏览器,所以问题很轻微。

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269