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 的 v-model用法实例
Nov 23 Vue.js
在vue项目中封装echarts的步骤
Dec 25 Vue.js
vue3.0中友好使用antdv示例详解
Jan 05 Vue.js
vue自定义组件实现双向绑定
Jan 13 Vue.js
Vue中的nextTick作用和几个简单的使用场景
Jan 25 Vue.js
vue使用transition组件动画效果的实例代码
Jan 28 Vue.js
Vue-router编程式导航的两种实现代码
Mar 04 Vue.js
Vue3中的Refs和Ref详情
Nov 11 Vue.js
一篇文章告诉你如何实现Vue前端分页和后端分页
Feb 18 Vue.js
Vue3如何理解ref toRef和toRefs的区别
Feb 18 Vue.js
vue整合百度地图显示指定地点信息
Apr 06 Vue.js
vue-treeselect的基本用法以及解决点击无法出现拉下菜单
Apr 30 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的超级变量$_POST获取HTML表单(HTML Form) 数据
2011/05/07 PHP
Yii框架getter与setter方法功能与用法分析
2019/10/22 PHP
火狐4、谷歌12不支持Jquery Validator的解决方法分享
2011/06/20 Javascript
jQuery基础框架浅入剖析
2012/12/27 Javascript
jquery中show()、hide()和toggle()用法实例
2015/01/15 Javascript
jQuery构造函数init参数分析
2015/05/13 Javascript
js 右侧浮动层效果实现代码(跟随滚动)
2015/11/22 Javascript
JavaScript事件代理和委托详解
2016/04/08 Javascript
再谈Javascript中的异步以及如何异步
2016/08/19 Javascript
用AngularJS的指令实现tabs切换效果
2016/08/31 Javascript
过期软件破解办法实例详解
2017/01/04 Javascript
Vue.js 2.0 移动端拍照压缩图片上传预览功能
2017/03/06 Javascript
解决vue 按钮多次点击重复提交数据问题
2018/05/10 Javascript
Vue中使用create-keyframe-animation与动画钩子完成复杂动画
2019/04/09 Javascript
layer ui插件显示tips时,修改字体颜色的实现方法
2019/09/11 Javascript
Python进阶-函数默认参数(详解)
2017/05/18 Python
python利用正则表达式排除集合中字符的功能示例
2017/10/10 Python
利用python批量修改word文件名的方法示例
2017/10/17 Python
python 简单搭建阻塞式单进程,多进程,多线程服务的实例
2017/11/01 Python
解决python3中自定义wsgi函数,make_server函数报错的问题
2017/11/21 Python
python3.6生成器yield用法实例分析
2019/08/23 Python
python 根据网易云歌曲的ID 直接下载歌曲的实例
2019/08/24 Python
使用Python测试Ping主机IP和某端口是否开放的实例
2019/12/17 Python
浅谈Python程序的错误:变量未定义
2020/06/02 Python
详解HTML5中的manifest缓存使用
2015/09/09 HTML / CSS
HTML5超炫酷粒子效果的进度条的实现示例
2019/08/23 HTML / CSS
奥地利智能家居和智能生活网上商店:tink.at
2019/10/07 全球购物
英国名牌男装店:Standout
2021/02/17 全球购物
旷课检讨书1000字
2014/02/14 职场文书
个人作风建设心得体会
2014/10/22 职场文书
世界红十字日活动总结
2015/02/10 职场文书
校本培训个人总结
2015/02/28 职场文书
2015夏季作息时间调整通知
2015/04/24 职场文书
超级实用的公文标题大全!
2019/07/19 职场文书
使用numpy实现矩阵的翻转(flip)与旋转
2021/06/03 Python
Python 快速验证代理IP是否有效的方法实现
2021/07/15 Python