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+element-ui的项目中封装dialog组件
Dec 11 Vue.js
vue3.0自定义指令(drectives)知识点总结
Dec 27 Vue.js
Vue中强制组件重新渲染的正确方法
Jan 03 Vue.js
vue 动态生成拓扑图的示例
Jan 03 Vue.js
手写Vue源码之数据劫持示例详解
Jan 04 Vue.js
Vue 实现可视化拖拽页面编辑器
Feb 01 Vue.js
vue首次渲染全过程
Apr 21 Vue.js
SSM VUE Axios详解
Oct 05 Vue.js
VUE使用draggable实现组件拖拽
Apr 06 Vue.js
vue判断按钮是否可以点击
Apr 09 Vue.js
vue修饰符.capture和.self的区别
Apr 22 Vue.js
vue本地构建热更新卡顿的问题“75 advanced module optimization”完美解决方案
Aug 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
PHP编程与应用
2006/10/09 PHP
php中使用DOM类读取XML文件的实现代码
2011/12/14 PHP
php实现邮件发送并带有附件
2014/01/24 PHP
PHP+APACHE实现网址伪静态
2015/02/22 PHP
php中mysql操作buffer用法详解
2015/03/19 PHP
WordPress中用于检索模版的相关PHP函数使用解析
2015/12/15 PHP
tp5(thinkPHP5)框架数据库Db增删改查常见操作总结
2019/01/10 PHP
laravel框架使用FormRequest进行表单验证,验证异常返回JSON操作示例
2020/02/18 PHP
document.compatMode介绍
2009/05/21 Javascript
使用jquery局部刷新(jquery.load)从数据库取出数据
2014/01/22 Javascript
jQuery中的$.ajax()方法应用
2014/05/06 Javascript
javascript 常见功能汇总
2015/06/11 Javascript
使用jquery实现仿百度自动补全特效
2015/07/23 Javascript
深入解析桶排序算法及Node.js上JavaScript的代码实现
2016/07/06 Javascript
10道典型的JavaScript面试题
2017/03/22 Javascript
ES6新特性之模块Module用法详解
2017/04/01 Javascript
捕获未处理的Promise错误方法
2017/10/13 Javascript
记一次webapck4 配置文件无效的解决历程
2018/09/19 Javascript
JavaScript实现简单动态表格
2020/12/02 Javascript
Taro小程序自定义顶部导航栏功能的实现
2020/12/17 Javascript
[02:40]DOTA2超级联赛专访430 从小就爱玩对抗性游戏
2013/06/18 DOTA
Python 抓取动态网页内容方案详解
2014/12/25 Python
Python基于pygame实现的font游戏字体(附源码)
2015/11/11 Python
Python中字典和集合学习小结
2017/07/07 Python
在Django的View中使用asyncio的方法
2019/07/12 Python
python进行参数传递的方法
2020/05/12 Python
Python 字符串池化的前提
2020/07/03 Python
python模拟点击玩游戏的实例讲解
2020/11/26 Python
Python3使用Selenium获取session和token方法详解
2021/02/16 Python
汇智创新科技发展有限公司
2015/12/06 面试题
测绘工程个人的自我评价
2013/11/23 职场文书
房屋出售协议书
2014/04/10 职场文书
难忘的一课教学反思
2014/04/30 职场文书
创业计划书之都市休闲农庄
2019/12/28 职场文书
python中opencv实现图片文本倾斜校正
2021/06/11 Python
win11无法添加打印机怎么办? 提示windows无法打开添加打印机的解决办法
2022/04/05 数码科技