提示:功能实现过了好久了,突然想起来一直没做个总结。好记性不如烂笔头,gogogo!
使用 element-ui 的
提示:以下是本篇文章正文内容,篇幅有限,出现的代码仅为关键部分的代码。
先上个最终实现的效果图吧!
在表头上鼠标右键,就能出现自定义列的操作菜单:
取消列的选中,就能隐藏对应的列:
列的显示隐藏信息被保存在浏览器的 localStorage 中了,只要不清缓存,下次就能沿用之前的列的显示/隐藏的设置。
// 实现动态表格列数据
// colOptions,colSelect中内容的顺序必须与表格中表头的内容顺序保持一致
// colOptions: 选中的列/显示的列
colOptions: parseArr("colOptions_inActs")
? parseArr("colOptions_inActs")
: [
"入库单号",
"入库批次",
"料箱号",
"货主代码",
"货主名称",
"厂商代码",
"厂商名称",
"状态",
"入库类型",
"入库员",
"入库时间"
],
// 完整列数据,用于生成菜单中的选项
colSelect: [
"入库单号",
"入库批次",
"料箱号",
"货主代码",
"货主名称",
"厂商代码",
"厂商名称",
"状态",
"入库类型",
"入库员",
"入库时间"
],
//
colData: parseObjArr("colData_inActs")
? parseObjArr("colData_inActs")
: [
{ title: "入库单号", istrue: true },
{ title: "入库批次", istrue: true },
{ title: "料箱号", istrue: true },
{ title: "货主代码", istrue: true },
{ title: "货主名称", istrue: true },
{ title: "厂商代码", istrue: true },
{ title: "厂商名称", istrue: true },
{ title: "状态", istrue: true },
{ title: "入库类型", istrue: true },
{ title: "入库员", istrue: true },
{ title: "入库时间", istrue: true }
],
// 标识设置菜单的显示与否
menuVisible: false,
// 设置菜单的显示位置与鼠标右键位置的偏移距离
top: 0,
left: 0,
为了便于与 localStorage 交互,封装了 4 个工具方法,代码也比较简单,就直接看下面的代码吧!
// 该文件中存放关于 json 的全局方法
/**
* 将对象数组存放到 localStorage 中
* @param {string} key: String 数据键名
* @param {Array[object]} data[]: [object] 原始数组数据
* @returns null
*/
export function stringifyObjArr(key, data) {
if (!Array.isArray(data)) {
return false
} else {
let formatData = []
for (let i = 0; i < data.length; i++) {
const element = data[i]
formatData.push(JSON.stringify(element))
}
localStorage.setItem(key, JSON.stringify(formatData))
}
}
/**
* 将数据从 localStorage 取出并转化为对象数组格式
* @param {string} key: String 数据键名
* @returns {Array[number|string]} data[]: [object] 数组数据
*/
export function parseObjArr(key) {
let rawData = JSON.parse(localStorage.getItem(key))
if (!rawData || !Array.isArray(rawData)) {
return false
} else {
let data = []
for (let i = 0; i < rawData.length; i++) {
const element = rawData[i]
data.push(JSON.parse(element))
}
return data
}
}
/**
* 数组转化为字符串 '[1, 2]' 后放入 localStorage
* @param {string} key: 数据键名
* @param {Array} data: 数组数据
* @returns null
*/
export function stringifyArr(key, data) {
if (!data) {
return false
} else {
localStorage.setItem(key, JSON.stringify(data))
}
}
/**
* 从 localStorage 中拿出 '[1, 2]' 并格式化为数组
* @param {string} key: 数据键名
* @returns {Array} : data[] 数组数据
*/
export function parseArr(key) {
return JSON.parse(localStorage.getItem(key))
}
这使用了 el-table 的 header-contextmenu 事件
:
关键代码如下:
<template>
<el-table
......
ref="table"
@header-contextmenu="contextmenu"
>
......
el-table>
<div
v-show="menuVisible"
:style="{top:top+ "px",left:left+ "px"}"
class="select-menu"
>
<p>定义显示的表格列p>
<el-checkbox-group v-model="colOptions" :min="1">
<el-checkbox v-for="item in colSelect" :key="item" :label="item" class="custom-checkbox" />
el-checkbox-group>
div>
template>
<script>
// 控制表格列数据的动态显示
contextmenu(row, event) {
this.menuVisible = false; // 先把右键菜单关死
this.menuVisible = true; // 显示自定义菜单
window.event.returnValue = false; // 取消浏览器右击默认事件
document.addEventListener("click", this.closeMenu);
// 获取鼠标点坐标,设置右击菜单位置
this.top = event.clientY;
this.left = event.clientX;
},
// 关闭设置菜单
closeMenu() {
this.menuVisible = false; // 关闭右键菜单
document.removeEventListener("click", this.closeMenu); // 取消监听事件
},
script>
在表格列上,使用 v-if
来控制列的显示/隐藏(用 v-show 是不起作用的,原因:display: table-cell 的优先级高于 display: none)。关键代码如下:
<el-table
......
ref="table"
@header-contextmenu="contextmenu"
>
<el-table-column
prop="storageNo"
v-if="colData[0].istrue"
label="入库单号"
width="280"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="batchNo"
v-if="colData[1].istrue"
label="入库批次"
width="120"
:show-overflow-tooltip="true"
/>
......
el-table>
监听 colOptions 数据,当设置数据变化时,更新与表格列关联的 colData 数据,并将更新后的设置数据保存到 localStorage 中。
watch: {
// 动态计算要显示的数据列
colOptions(valArr) {
var arr = this.colSelect.filter(i => valArr.indexOf(i) < 0); // 未选中
this.colData.filter(i => {
if (arr.indexOf(i.title) !== -1) {
i.istrue = false;
} else {
i.istrue = true;
}
});
// 本地保存数据列显示与否的设置数据
stringifyObjArr("colData_inActs", this.colData);
stringifyArr("colOptions_inActs", valArr);
}
},
这里要特别注意,列设置数据与实际列的顺序一定要保持一致。
到步骤 3,其实已经基本完成了客户端自定义列的显示隐藏功能了,但是,在实际使用中,还存在着一些问题。下面是我遇到的问题以及找到的解决办法。
设置列显示/隐藏,的确实现了,可是,发现了新的问题:表头抖动的厉害,表格出现了样式错乱的情况,如下图:
在官方文档中,找到了解决方案:
在表格更新前,使用 doLayout 方法
来对表格进行重新布局,解决样式错乱的问题,关键代码如下:
beforeUpdate() {
// 重新布局表格
this.$nextTick(() => {
this.$refs.table.doLayout();
});
},
最后,简单总结下吧:
列设置数据
,注意顺序一致;header-contextmenu 方法
,调出右键菜单;v-if
控制表格列的显示/隐藏;doLayout 方法
在更新表格前,重新布局表格;localStorage
来实现列设置数据的持久化(如果有需要,可以改为后端保存列设置数据,这样就不用担心清了缓存了!)