vue完美实现el-table列宽自适应


Posted in Vue.js onMay 08, 2021

背景

Element UI 是 PC 端比较流行的 Vue.js UI 框架,它的组件库基本能满足大部分常见的业务需求。但有时候会有一些定制性比较高的需求,组件本身可能没办法满足。最近在项目里就碰到了。

很多页面都需要用到表格组件el-table。如果没有给el-table-column指定宽度,默认情况下会平均分配给剩余的列。在列数比较多的情况,如果el-table宽度限定在容器内,单元格里的内容就会换行。强制不换行,内容要么在单元格内滚动,要么就会溢出或被截断。

产品想要的效果是:内容保持单行显示,列间距保持一致,表格超出容器允许水平滚动。el-table-column是支持设置固定宽度的,在内容宽度可预知的情况下,也能满足这个需求。问题就在于如何让列宽动态适应内容的宽度。在官方文档也没找到这样的选项,应该是组件本身不支持。

技术方案

于是想到了动态计算内容宽度的方案。网上也有人提过这个思路,做法是根据内容字符数来计算宽度。这种方法有几个局限:

  • 内容必须是文本
  • 不同字符宽度不一,结算结果不够准确
  • 需要在渲染前操作数据,不利于解耦

我采用了另一种思路,还是动态计算内容宽度,但是根据实际渲染后的 DOM 元素宽度,这样就能解决上面三个问题。

具体怎么做呢?通过查看渲染后的 DOM 元素发现,el-table 的表头和内容分别用了一个原生table,通过colgroup设置每列的宽度。就从这里入手,col的name属性值和对应的 td的class值是一致的,这样就可以遍历对应列的所有单元格,找出宽度最大的单元格,用它的内容宽度加上一个边距作为该列的宽度。

vue完美实现el-table列宽自适应

具体实现

怎么计算内容宽度呢?这是个比较关键的步骤。渲染后的每个单元格有个.cell类,用white-space: nowrap; overflow: auto;设置为不允许换行,内容超出后可滚动,同时设置display: inline-block;以便计算实际内容宽度。这样,最终的宽度可通过.cell元素的scrollWidth属性得到。

function adjustColumnWidth(table) {
  const colgroup = table.querySelector("colgroup");
  const colDefs = [...colgroup.querySelectorAll("col")];
  colDefs.forEach((col) => {
    const clsName = col.getAttribute("name");
    const cells = [
      ...table.querySelectorAll(`td.${clsName}`),
      ...table.querySelectorAll(`th.${clsName}`),
    ];
    // 忽略加了"leave-alone"类的列
    if (cells[0]?.classList?.contains?.("leave-alone")) {
      return;
    }
    const widthList = cells.map((el) => {
      return el.querySelector(".cell")?.scrollWidth || 0;
    });
    const max = Math.max(...widthList);
    const padding = 32;
    table.querySelectorAll(`col[name=${clsName}]`).forEach((el) => {
      el.setAttribute("width", max + padding);
    });
  });
}

中间的探索过程比较繁琐,但最终的代码实现却非常简洁。在什么时候触发列宽计算呢?自然是组件渲染完成后。为了方便重用,我采用了 Vue 自定义指令的方式。

Vue.directive("fit-columns", {
  update() {},
  bind() {},
  inserted(el) {
    setTimeout(() => {
      adjustColumnWidth(el);
    }, 300);
  },
  componentUpdated(el) {
    el.classList.add("r-table");
    setTimeout(() => {
      adjustColumnWidth(el);
    }, 300);
  },
  unbind() {},
});

更进一步,我封装了一个 Vue 插件叫v-fit-columns,已经发布到 npm 仓库,直接安装即可使用。
安装:

npm install v-fit-columns --save

引入:

import Vue from 'vue';
import Plugin from 'v-fit-columns';
Vue.use(Plugin);

使用:

<el-table v-fit-columns>
  <el-table-column label="No." type="index" class-name="leave-alone"></el-table-column>
  <el-table-column label="Name" prop="name"></el-table-column>
  <el-table-column label="Age" prop="age"></el-table-column>
</el-table>

源码仓库在这:https://github.com/kaysonli/v-fit-columns ,欢迎各位不吝赐教和 Star!

总结

这个方案多少有点 Hack 的意味,只顾实现需求,可能在其他方面还有点瑕疵,比如渲染完后会稍微闪一下(因为要重新调整宽度,会出现 reflow)。不过从最终实现的效果来看,还算令人满意

以上就是vue完美实现el-table列宽自适应的详细内容,更多关于vue实现el-table列宽自适应的资料请关注三水点靠木其它相关文章!

Vue.js 相关文章推荐
vue + el-form 实现的多层循环表单验证
Nov 25 Vue.js
使用vue编写h5公众号跳转小程序的实现代码
Nov 27 Vue.js
浅谈Vue使用Elementui修改默认的最快方法
Dec 05 Vue.js
vue项目中openlayers绘制行政区划
Dec 24 Vue.js
vue实现登录功能
Dec 31 Vue.js
vue 项目@change多个参数传值多个事件的操作
Jan 29 Vue.js
Vue中避免滥用this去读取data中数据
Mar 02 Vue.js
idea编译器vue缩进报错问题场景分析
Jul 04 Vue.js
vue中div禁止点击事件的实现
Apr 02 Vue.js
vue 自定义的组件绑定点击事件
Apr 21 Vue.js
Vue Mint UI mt-swipe的使用方式
Jun 05 Vue.js
关于Vue Router的10条高级技巧总结
May 06 #Vue.js
Vue项目中如何封装axios(统一管理http请求)
May 02 #Vue.js
使用vue-element-admin框架从后端动态获取菜单功能的实现
vue使用v-model进行跨组件绑定的基本实现方法
关于vue中如何监听数组变化
vue实现简单数据双向绑定
Apr 28 #Vue.js
vue引入Excel表格插件的方法
Apr 28 #Vue.js
You might like
制作美丽的拉花
2021/03/03 冲泡冲煮
深入分析PHP引用(&amp;)
2014/09/04 PHP
浅谈PHP链表数据结构(单链表)
2016/06/08 PHP
PHP sleep()函数, usleep()函数
2016/08/25 PHP
PHP获取访问设备信息的方法示例
2019/02/20 PHP
jQuery获取地址栏参数插件(模仿C#)
2010/10/26 Javascript
JavaScript动态操作表格实例(添加,删除行,列及单元格)
2013/11/25 Javascript
jQuery提示插件alertify使用指南
2015/04/21 Javascript
js 动态添加元素(div、li、img等)及设置属性的方法
2016/07/19 Javascript
JS使用正则表达式过滤多个词语并替换为相同长度星号的方法
2016/08/03 Javascript
JS控制静态页面之间传递参数获取参数并应用的简单实例
2016/08/10 Javascript
jquery实现的回旋滚动效果完整实例【附demo源码下载】
2016/09/20 Javascript
js中小数向上取整数,向下取整数,四舍五入取整数的实现(必看篇)
2017/02/13 Javascript
angular中实现li或者某个元素点击变色的两种方法
2017/07/27 Javascript
BetterScroll 在移动端滚动场景的应用
2017/09/18 Javascript
JavaScript数据结构之双向链表和双向循环链表的实现
2017/11/28 Javascript
详解Angular结合zTree异步加载节点数据
2018/01/20 Javascript
javascript的this关键字详解
2019/05/20 Javascript
微信小程序实现张图片合成为一张并下载
2019/07/16 Javascript
原生JS实现弹幕效果的简单操作指南
2020/11/10 Javascript
[01:36]DOTA2完美大师赛趣味视频之与队友相处的十万个技巧
2017/11/19 DOTA
Python操作CouchDB数据库简单示例
2015/03/10 Python
深入探究Python中变量的拷贝和作用域问题
2015/05/05 Python
Django中的“惰性翻译”方法的相关使用
2015/07/27 Python
Python中集合的内建函数和内建方法学习教程
2015/08/19 Python
django利用request id便于定位及给日志加上request_id
2018/08/26 Python
pandas重新生成索引的方法
2018/11/06 Python
Python3.0中普通方法、类方法和静态方法的比较
2019/05/03 Python
Django的Modelforms用法简介
2019/07/27 Python
使用Pandas对数据进行筛选和排序的实现
2019/07/29 Python
英国在线药房:Chemist.co.uk
2019/03/26 全球购物
保护环境的建议书
2014/03/12 职场文书
宪法宣传周工作方案
2014/05/26 职场文书
给老婆道歉的话
2015/01/20 职场文书
公安机关起诉意见书
2015/05/20 职场文书
Python 循环读取数据内存不足的解决方案
2021/05/25 Python