问题描述

用Element Plus框架进行网站的搭建,用到了组件Table,进行列表数据的展示,但由于数据内容过长导致列换行了,自己感觉不美观,想处理下,由于也是才用这个框架对属性没有认真的看,导致走了不少弯路,其实框架本身已经给我们提供了处理办法。

弯路解决(不推荐)

自己参考了一个开源的一个插件:https://github.com/kaysonli/v-fit-columns,此插件可实现el-table-column宽度自适应但基于vue2开发的。但Element Plus框架是基于vue3的所以我对这个源码进行了修改以适应vue3。实际上就是自定义命令v-fit-columns来对列进行扩宽处理,具体可以参考下面的代码。

我的项目是基于Vue CLI构建的。

相关代码

// fit-table-columns.js
import "../assets/style/fit-table-columns.css"

/**
 * 自定义命令-关于el-table列固定(函数指令`v-fit-columns`)
 * @param app
 */
export default (app) => {
    app.directive('fit-columns', {
        // 指令具有一组生命周期钩子:
        // 在绑定元素的 attribute 或事件监听器被应用之前调用
        created() {
        },
        // 在绑定元素的父组件挂载之前调用
        beforeMount() {
        },
        // 在绑定元素的父组件挂载之后调用
        mounted(el, binding) {
            setTimeout(() => {
                adjustColumnWidth(el, binding.value);
            }, 300);
        },
        // 在包含组件的 VNode 更新之前调用
        beforeUpdate() {
        },
        // 在包含组件的 VNode 及其子组件的 VNode 更新之后调用
        updated(el, binding) {
            el.classList.add("r-table");
            setTimeout(() => {
                adjustColumnWidth(el, binding.value);
            }, 300);
        },
        // 在绑定元素的父组件卸载之前调用
        beforeUnmount() {
        },
        // 在绑定元素的父组件卸载之后调用
        unmounted() {
        }
    })
}

/**
 * 调整列宽
 * @param table 使用调整列宽命令的table
 * @param padding 0
 */
function adjustColumnWidth(table, padding = 0) {
    // 获取table的colgroup节点DOM
    const colgroup = table.querySelector("colgroup");
    // 获取colgroup节点所有的列DOM
    const colDefs = [...colgroup.querySelectorAll("col")];
    colDefs.forEach((col) => {
        const clsName = col.getAttribute("name");
        // cells[0]为td的className=`${clsName}`的所有DOM
        // cells[1]为th的className=`${clsName}`的所有DOM
        const cells = [
            ...table.querySelectorAll(`td.${clsName}`),
            ...table.querySelectorAll(`th.${clsName}`),
        ];
        // 判断class="leave-alone"是否存在,存在则不需要设置此功能
        if (cells[0]?.classList?.contains?.("leave-alone")) {
            return;
        }
        // 通过css选择器获取class="cell"的DOM的宽度
        const widthList = cells.map((el) => {
            return el.querySelector(".cell")?.scrollWidth || 0;
        });
        // 获取一个最大的宽度
        const max = Math.max(...widthList);
        table.querySelectorAll(`col[name=${clsName}]`).forEach((el) => {
            const oldWidth = el.offsetWidth;
            // 如果宽度没变就不添加padding
            if (max > oldWidth) {
                el.setAttribute("width", max + padding);
            }
        });
    });
}
// fit-table-columns.css
/** 表格显示内容的div样式 */
.el-table.r-table .cell {
    display: inline-block;
    white-space: nowrap;
    width: auto;
    overflow: auto;
}
/** 表头外的显示数据的div样式 */
.el-table.r-table .el-table__body-wrapper {
    overflow-x: auto;
}
// main.js
import {createApp} from 'vue'
import axios from 'axios'
import VueAxios from 'vue-axios'
import router from './router'
import fitTableColumns from './plugins/fit-table-columns'
import App from './App.vue'

const app = createApp(App).use(router)
app.use(VueAxios, axios)
// 注册自定义命令`v-fit-columns`
fitTableColumns(app)
app.mount('#app')
// tableList.vue
<template>
	<el-table :data="elTable.tableData"
                stripe
                border
                height="250"
                v-fit-columns
                >
        <el-table-column type="selection" width="55" />
        <el-table-column type="index" label="序号" width="55"/>
        <el-table-column v-for="(item,index) in elTable.tableLabels" :key="index"
                         :property="item.property"
                         :label="item.label"
                         :width="item.width"
        >
        </el-table-column>
      </el-table>
</template>
<script>
export default {
  name: "tableList",
  data() {
    return {
      elTable: {
        tableLabels: [
          {label: '表名称', property: 'tableName'},
          {label: '表描述', property: 'tableComment'},
          {label: '创建时间', property: 'createTimeFormat'},
          {label: '更新时间', property: 'updateTimeFormat'}
        ],
        tableData: [{
			"createTimeFormat": "2022-04-07 15:27:06",
			"updateTimeFormat": null,
			"tableName": "oauth2_authorization_consent",
			"tableComment": ""
		},
		{
			"createTimeFormat": "2022-04-07 15:27:31",
			"updateTimeFormat": "2022-05-25 09:34:08",
			"tableName": "oauth2_registered_client",
			"tableComment": ""
		}]
      }
    }
  }
}
</script>

换行前table样式

表名称是换行的
在这里插入图片描述

处理后table样式

确实不换行了,列变宽了可以展示全部的数据了,但感觉还是不是很好,因为如果数据很多岂不是行变得很长。还有就是首次加载时,updated方法会执行多次导致table频繁闪动。
在这里插入图片描述

官方处理方式(推荐)

有这么个属性:show-overflow-tooltip,文档说明: 若需要单行显示可以使用 show-overflow-tooltip 属性,它接受一个 Boolean, 为 true 时多余的内容会在 hover 时以 tooltip 的形式显示出来。

修改代码

<template>
	<el-table :data="elTable.tableData"
                stripe
                border
                height="250"
                >
        <el-table-column type="selection" width="55" />
        <el-table-column type="index" label="序号" width="55"/>
        <el-table-column v-for="(item,index) in elTable.tableLabels" :key="index"
                         :property="item.property"
                         :label="item.label"
                         :width="item.width"
                         show-overflow-tooltip
        >
        </el-table-column>
      </el-table>
</template>

页面效果

加了show-overflow-tooltip我们再来看一看效果,列没有加宽,而是把溢出的数据用省略号替换并用Tooltip 组件的文字提示。
感觉不错,反正达到我想要的效果。
在这里插入图片描述

总结

一定要用认真看官方的文档,以免走弯路。但我这次还好起码学到了vue3关于自定义命令的相关知识。

Logo

前往低代码交流专区

更多推荐