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 26 Vue.js
在Vue中使用CSS3实现内容无缝滚动的示例代码
Nov 27 Vue.js
vuex Module将 store 分割成模块的操作
Dec 07 Vue.js
vue实现一个获取按键展示快捷键效果的Input组件
Jan 13 Vue.js
vue element和nuxt的使用技巧分享
Jan 14 Vue.js
学习 Vue.js 遇到的那些坑
Feb 02 Vue.js
vue实现禁止浏览器记住密码功能的示例代码
Feb 03 Vue.js
vue 使用 v-model 双向绑定父子组件的值遇见的问题及解决方案
Mar 01 Vue.js
VUE实现吸底按钮
Mar 04 Vue.js
vue数据字典取键值项目的字典问题
Apr 12 Vue.js
vue中data里面的数据相互使用方式
Jun 05 Vue.js
VUE递归树形实现多级列表
Jul 15 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
FCKeditor添加自定义按钮
2008/03/27 PHP
CI框架中libraries,helpers,hooks文件夹详细说明
2014/06/10 PHP
PHP模板引擎Smarty内建函数详解
2016/04/11 PHP
php文件操作之文件写入字符串、数组的方法分析
2019/04/15 PHP
将jQuery应用于login页面的问题及解决
2009/10/17 Javascript
DD_belatedPNG,IE6下PNG透明解决方案(国外)
2010/12/06 Javascript
Jquery Validate 正则表达式实用验证代码大全
2013/08/23 Javascript
jQuery避免$符和其他JS库冲突的方法对比
2014/02/20 Javascript
NODE.JS加密模块CRYPTO常用方法介绍
2014/06/05 Javascript
jQuery中first()方法用法实例
2015/01/06 Javascript
详解Bootstrap创建表单的三种格式(一)
2016/01/04 Javascript
Angular实现双向折叠列表组件的示例代码
2017/11/21 Javascript
zTree节点文字过多的处理方法
2017/11/24 Javascript
JavaScript Dom 绑定事件操作实例详解
2019/10/02 Javascript
vue把输入框的内容添加到页面的实例讲解
2019/11/11 Javascript
vue实现购物车列表
2020/06/30 Javascript
浅谈js中的attributes和Attribute的用法与区别
2020/07/16 Javascript
win7下python3.6安装配置方法图文教程
2018/07/31 Python
对python中dict和json的区别详解
2018/12/18 Python
详解python函数的闭包问题(内部函数与外部函数详述)
2019/05/17 Python
详解PANDAS 数据合并与重塑(join/merge篇)
2019/07/09 Python
Python键鼠操作自动化库PyAutoGUI简介(小结)
2020/05/17 Python
如何用Python徒手写线性回归
2021/01/25 Python
CSS3的 fit-content实现水平居中
2017/09/07 HTML / CSS
div或img图片高度随宽度自适应的方法
2020/02/06 HTML / CSS
高三生物教学反思
2014/01/25 职场文书
优秀实习生感言
2014/03/01 职场文书
入党积极分子自我鉴定范文
2014/03/25 职场文书
绿色环保演讲稿
2014/05/10 职场文书
优秀教师单行材料
2014/12/16 职场文书
寻衅滋事罪辩护词
2015/05/21 职场文书
2016年重阳节慰问信
2015/12/01 职场文书
关于CSS浮动与取消浮动的问题
2021/06/28 HTML / CSS
详解JavaScript中Arguments对象用途
2021/08/30 Javascript
python 多态 协议 鸭子类型详解
2021/11/27 Python
聊聊基于pytorch实现Resnet对本地数据集的训练问题
2022/03/25 Python