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实现购物小球抛物线的方法实例
Nov 22 Vue.js
vue3.0中setup使用(两种用法)
Dec 02 Vue.js
vue实现滚动鼠标滚轮切换页面
Dec 13 Vue.js
vue实现购物车的小练习
Dec 21 Vue.js
Vue实现随机验证码功能
Dec 29 Vue.js
vue+elementui通用弹窗的实现(新增+编辑)
Jan 07 Vue.js
基于vuex实现购物车功能
Jan 10 Vue.js
详解template标签用法(含vue中的用法总结)
Jan 12 Vue.js
Vue实现多页签组件
Jan 14 Vue.js
Vue2.0搭建脚手架
Mar 13 Vue.js
vue cli4中mockjs在dev环境和build环境的配置详情
Apr 06 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
第十四节--命名空间
2006/11/16 PHP
js下函数般调用正则的方法附代码
2008/06/22 PHP
百万级别知乎用户数据抓取与分析之PHP开发
2015/09/28 PHP
PHP实现字符串的全排列详解
2019/04/24 PHP
javascript事件模型代码
2007/07/01 Javascript
JS 事件绑定函数代码
2010/04/28 Javascript
JavaScript实现网页图片等比例缩放实现代码及调用方式
2013/02/25 Javascript
JS 实现导航栏悬停效果
2013/09/23 Javascript
jquery使用hide方法隐藏指定id的元素
2015/03/30 Javascript
Javascript中typeof 用法小结
2015/05/12 Javascript
jQuery中extend()和fn.extend()方法详解
2015/06/03 Javascript
在Javascript中处理字符串之big()方法的使用
2015/06/08 Javascript
随机生成10个不重复的0-100的数字(实例讲解)
2017/08/16 Javascript
Vue filter介绍及其使用详解
2017/10/21 Javascript
React Native实现地址挑选器功能
2017/10/24 Javascript
使用vue-router设置每个页面的title方法
2018/02/11 Javascript
BootStrap table实现表格行拖拽效果
2018/12/01 Javascript
ES6顶层对象、global对象实例分析
2019/06/14 Javascript
详解Vue中组件传值的多重实现方式
2019/08/16 Javascript
ESLint 是如何检查 .vue 文件的
2020/11/30 Vue.js
[02:22]《新闻直播间》2017年08月14日
2017/08/15 DOTA
跟老齐学Python之再深点,更懂list
2014/09/20 Python
python基础教程之匿名函数lambda
2017/01/17 Python
Pycharm学习教程(7)虚拟机VM的配置教程
2017/05/04 Python
Python集成开发工具Pycharm的安装和使用详解
2020/03/18 Python
类的核心特性有哪些
2014/01/01 面试题
党支部公开承诺书
2014/03/28 职场文书
水电维修专业推荐信
2014/09/06 职场文书
教师党员个人整改措施材料
2014/09/16 职场文书
民主评议党员总结
2014/10/20 职场文书
幼儿园大班毕业评语
2014/12/31 职场文书
英语教师个人总结
2015/02/09 职场文书
小组口号霸气押韵
2015/12/24 职场文书
护士自荐信范文(2016推荐篇)
2016/01/28 职场文书
MySQL索引知识的一些小妙招总结
2021/05/10 MySQL
mybatis3中@SelectProvider传递参数方式
2021/08/04 Java/Android