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-cli 创建模板项目
Nov 19 Vue.js
Vue如何跨组件传递Slot的实现
Dec 14 Vue.js
vue实现图片裁剪后上传
Dec 16 Vue.js
vue3使用vue-count-to组件的实现
Dec 25 Vue.js
vue+vant 上传图片需要注意的地方
Jan 03 Vue.js
基于Vue2实现移动端图片上传、压缩、拖拽排序、拖拽删除功能
Jan 05 Vue.js
vue element el-transfer增加拖拽功能
Jan 15 Vue.js
如何在vue 中使用柱状图 并自修改配置
Jan 21 Vue.js
学习 Vue.js 遇到的那些坑
Feb 02 Vue.js
Vue接口封装的完整步骤记录
May 14 Vue.js
vue.js Router中嵌套路由的实用示例
Jun 27 Vue.js
Vue中Object.assign清空数据报错的解决方案
Mar 03 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操作JSON格式数据的实现代码
2011/12/24 PHP
Thinkphp使用mongodb数据库实现多条件查询方法
2014/06/26 PHP
PHP多进程之pcntl_fork的实例详解
2017/10/15 PHP
PHP explode()函数用法讲解
2019/02/15 PHP
一些常用的Javascript函数
2006/12/22 Javascript
淘宝搜索框效果实现分析
2011/03/05 Javascript
js分页代码分享
2014/04/28 Javascript
JavaScript字符串对象toUpperCase方法入门实例(用于把字母转换为大写)
2014/10/17 Javascript
以JavaScript来实现WordPress中的二级导航菜单的方法
2015/12/14 Javascript
json定义及jquery操作json的方法
2016/09/29 Javascript
微信小程序 页面跳转传参详解
2016/10/28 Javascript
函数四种调用模式以及其中的this指向
2017/01/16 Javascript
vue.js项目中实用的小技巧汇总
2017/11/29 Javascript
JavaScrip关于创建常量的知识点
2017/12/07 Javascript
jQuery阻止事件冒泡实例分析
2018/07/03 jQuery
微信实现自动跳转到用其他浏览器打开指定APP下载
2019/02/15 Javascript
vue穿梭框实现上下移动
2021/01/29 Vue.js
[15:15]教你分分钟做大人:狙击手
2014/10/30 DOTA
[04:29]DOTA2亚洲邀请赛小组赛第一日 TOP10精彩集锦
2015/02/01 DOTA
python中split方法用法分析
2015/04/17 Python
Python学习小技巧总结
2018/06/10 Python
Python 中使用 PyMySQL模块操作数据库的方法
2019/11/10 Python
pytorch实现CNN卷积神经网络
2020/02/19 Python
Python3安装模块报错Microsoft Visual C++ 14.0 is required的解决方法
2020/07/28 Python
python爬虫 requests-html的使用
2020/11/30 Python
python 利用百度API识别图片文字(多线程版)
2020/12/14 Python
HTML5到底会有什么发展?HTML5的前景展望
2015/07/07 HTML / CSS
Omio法国:全欧洲低价大巴、火车和航班搜索和比价
2017/11/13 全球购物
美国酒店控股公司:Choice Hotels
2018/06/15 全球购物
weblogic面试题
2016/03/07 面试题
网络编辑岗位职责范本
2014/02/10 职场文书
关于安全演讲稿
2014/05/09 职场文书
2014年司法所工作总结
2014/11/22 职场文书
幼儿园国培研修日志
2015/11/13 职场文书
浅谈由position属性引申的css进阶讨论
2021/05/25 HTML / CSS
英国数字版游戏销量周榜公布 《小缇娜的奇幻之地》登顶
2022/04/03 其他游戏