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 相关文章推荐
springboot+vue实现文件上传下载
Nov 17 Vue.js
如何正确解决VuePress本地访问出现资源报错404的问题
Dec 03 Vue.js
在vue中使用inheritAttrs实现组件的扩展性介绍
Dec 07 Vue.js
vue项目中openlayers绘制行政区划
Dec 24 Vue.js
vue 实现click同时传入事件对象和自定义参数
Jan 29 Vue.js
Vue SPA 首屏优化方案
Feb 26 Vue.js
Vue和Flask通信的实现
May 19 Vue.js
vue.js Router中嵌套路由的实用示例
Jun 27 Vue.js
vue+element ui实现锚点定位
Jun 29 Vue.js
详解Vue router路由
Nov 20 Vue.js
VUE中的v-if与v-show区别介绍
Mar 13 Vue.js
vue选项卡切换的实现案例
Apr 11 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
DISCUZ在win2003环境下 Unable to access ./include/common.inc.php in... 的问题终极解决方案
2011/11/21 PHP
PHP获取服务器端信息的方法
2014/11/28 PHP
PHP关于foreach复制知识点总结
2019/01/28 PHP
Yii框架操作cookie与session的方法实例详解
2019/09/04 PHP
PHP防止sql注入小技巧之sql预处理原理与实现方法分析
2019/12/13 PHP
JQuery 获取和设置Select选项的代码
2010/02/07 Javascript
深入理解JavaScript系列(22):S.O.L.I.D五大原则之依赖倒置原则DIP详解
2015/03/05 Javascript
javascript实现控制浏览器全屏
2015/03/30 Javascript
Angular2里获取(input file)上传文件的内容的方法
2017/09/05 Javascript
arcgis for js栅格图层叠加(Raster Layer)问题
2017/11/22 Javascript
vue组件中的数据传递方法
2018/05/14 Javascript
angular 内存溢出的问题解决
2018/07/12 Javascript
解决echarts的多个折现数据出现坐标和值对不上的问题
2018/12/28 Javascript
深入浅析JavaScript中的in关键字和for-in循环
2020/04/20 Javascript
JS严格模式原理与用法实例分析
2020/04/27 Javascript
[04:48]DOTA2上海特锦赛小组赛第三日 TOP10精彩集锦
2016/02/28 DOTA
python正则匹配查询港澳通行证办理进度示例分享
2013/12/27 Python
在Django中限制已登录用户的访问的方法
2015/07/23 Python
详解Python中映射类型(字典)操作符的概念和使用
2015/08/19 Python
qpython3 读取安卓lastpass Cookies
2016/06/19 Python
Python定时器实例代码
2017/11/01 Python
Python 快速实现CLI 应用程序的脚手架
2017/12/05 Python
java中两个byte数组实现合并的示例
2018/05/09 Python
python+opencv打开摄像头,保存视频、拍照功能的实现方法
2019/01/08 Python
python使用yield压平嵌套字典的超简单方法
2019/11/02 Python
TensorFlow保存TensorBoard图像操作
2020/06/23 Python
Python 字典一个键对应多个值的方法
2020/09/29 Python
如何Tkinter模块编写Python图形界面
2020/10/14 Python
Python实现树莓派摄像头持续录像并传送到主机的步骤
2020/11/30 Python
python用700行代码实现http客户端
2021/01/14 Python
《匆匆》教学反思
2014/02/22 职场文书
2015年仓库工作总结
2015/04/09 职场文书
详解python字符串驻留技术
2021/05/21 Python
世界各国短波电台对东亚播送时间频率表(SW)
2021/06/28 无线电
css3新特性的应用示例分析
2022/03/16 HTML / CSS
「天才王子的赤字国家重生术」妮妮姆·拉雷粘土人开订
2022/03/21 日漫