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生命周期的深入理解
Dec 03 Vue.js
vue 实现图片懒加载功能
Dec 31 Vue.js
vuex的使用步骤
Jan 06 Vue.js
vue自定义组件实现双向绑定
Jan 13 Vue.js
如何使用RoughViz可视化Vue.js中的草绘图表
Jan 30 Vue.js
vue+django实现下载文件的示例
Mar 24 Vue.js
vue实现同时设置多个倒计时
May 20 Vue.js
vue使用Google Recaptcha验证的实现示例
Aug 23 Vue.js
vue 实现弹窗关闭后刷新效果
Apr 08 Vue.js
分享一个vue实现的记事本功能案例
Apr 11 Vue.js
vue动态绑定style样式
Apr 20 Vue.js
vue实现input输入模糊查询的三种方式
Aug 14 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来自动调用不同服务器上的flash
2006/10/09 PHP
apache2.2.4+mysql5.0.77+php5.2.8安装精简
2009/04/29 PHP
destoon实现VIP排名一直在前面排序的方法
2014/08/21 PHP
Zend Framework框架Smarty扩展实现方法
2016/03/22 PHP
php文件上传类完整实例
2016/05/14 PHP
Yii框架的路由配置方法分析
2019/09/09 PHP
jquery 表单下所有元素的隐藏
2009/07/25 Javascript
类似天猫商品详情随浏览器移动的示例代码
2014/02/27 Javascript
javascript刷新父页面的各种方法汇总
2014/09/03 Javascript
自己动手制作基于jQuery的Web页面加载进度条插件
2016/06/03 Javascript
必备的JS调试技巧汇总
2016/07/20 Javascript
JS写XSS cookie stealer来窃取密码的步骤详解
2017/11/20 Javascript
JS实现的tab切换并显示相应内容模块功能示例
2019/08/03 Javascript
Vue分页效果与购物车功能
2019/12/13 Javascript
微信小程序吸底区域适配iPhoneX的实现
2020/04/09 Javascript
Javascript实现鼠标移入方向感知
2020/06/24 Javascript
js 数据类型判断的方法
2020/12/03 Javascript
python通过opencv实现批量剪切图片
2017/11/13 Python
Django models.py应用实现过程详解
2019/07/29 Python
Python绘制热力图示例
2019/09/27 Python
python中round函数如何使用
2020/06/19 Python
python文件及目录操作代码汇总
2020/07/08 Python
表单button的outline在firefox浏览器下的问题
2012/12/24 HTML / CSS
Html5 localStorage入门教程
2018/04/26 HTML / CSS
荷兰优雅女装网上商店:Heine
2016/11/14 全球购物
金牌葡萄酒俱乐部:Gold Medal Wine Club
2017/11/02 全球购物
日本AOKI官方商城:AOKI西装
2020/06/11 全球购物
文员岗位职责
2013/11/09 职场文书
高中军训感想800字
2014/02/23 职场文书
大学生实习鉴定评语
2014/04/25 职场文书
硕士学位论文评语
2014/12/31 职场文书
给男朋友的道歉短信
2015/05/12 职场文书
小学教研工作总结2015
2015/05/13 职场文书
酒店员工管理制度
2015/08/05 职场文书
保外就医申请书范文
2015/08/06 职场文书
基于Python实现nc批量转tif格式
2022/08/14 Python