这个项目是一个管理后台,表格字段太多了,页面容纳不下,所以产品希望能增加一个用户设置表格字段的功能,自定义查看对应的参数,因为项目已经上线,所以希望能前端解决,缩短开发时间。
该项目基于vue-element-admin,感谢尤大大和花裤衩。
1. 设置是全局的,放vuex,然后根据路由来匹配当前页面的表格参数。
数据格式如下:
userDefined: [
{
path: "/order/list", //路径,用来匹配当前页面
list: [
{
label: "客户备注", //表格列名
align: "center", //文字居中
prop: "remark", //参数名
isShow: true, //用来过滤列的,这个属于自定义,不是表格要的
},
...省略,
{
label: "审核时间", //表格列名
width: "140", //表格宽度
align: "center", //文字居中
prop: "verifyTime", //参数名
formatter: "formatTime", //表格内容格式化方法,因为列要用到循环,但是格式化方法不一样,这里就存方法名。
isShow: true,
},
],
},
{
path: "/order/refund",
list: [
{
label: "退款编号",
width: "180",
align: "center",
prop: "sn",
fixed: "left",
isShow: true,
},
...省略,
{
label: "退款原因",
align: "center",
width: "160",
formatter: "formatRefundReason",
prop: "refundReason",
isShow: true,
},
],
},
],
2. 侧边栏组件:也就是下面这个展示字段名的组件,里面就是一个checkbbox(全选)和一个el-checkbox-group(参数列表)。
结构如下:
<div class="setting">
<el-checkbox
v-model="checkAll"
@change="handleCheckAllChange" //全选,没啥说的,就是把所有的参数里面的isShow都改成true。
>全选</el-checkbox
>
<el-checkbox-group
v-model="userDefinedList" //绑定的数组
style="display: flex; flex-direction: column; gap: 6px; margin: 6px 0"
@change="handleCheckedCitiesChange" //用来存localstrage。
>
<el-checkbox
v-for="item in userDefinedObj.list"
:label="item.prop"
:key="item.prop"
>{{ item.label }}</el-checkbox
>
</el-checkbox-group>
</div>
</template>
3. watch,监听路由,获取当前页面的参数。
$route(value) {
this.currentPath = value.path; //路由的path
this.routeChange();
},
},
获取当前页面的表格参数,userDefined就是上面定义的数组,这个数组会存localstrage。
const data = this.userDefined.find((item) =>item.path == this.currentPath);
this.userDefinedObj = data?data.list:[];
},
4.全选和切换选择的时候,都会修改数组中的isShow字段,替换vuex中数据,存到localstrage。
// 全选事件
handleCheckAllChange() {
this.checkChange();
},
checkChange() {
const arr = this.userDefinedList.map((item) => item);
//userDefined数组第一次是从localstrage中获取,如果没有,就给全部的,字段默认全部显示。
this.userDefined.forEach((item) => {
if (item.path == this.currentPath) {
item.list.forEach((i) => {
if (arr.includes(i.prop)) {
i.isShow = true;
} else {
i.isShow = false;
}
});
}
});
const list = Array.prototype.slice.call(this.userDefined);
localStorage.setItem("userDefined", JSON.stringify(this.userDefined)); //存本地
this.saveParamsList(list); //修改vuex中的数据
},
// 单个选择事件
handleCheckedCitiesChange() {
this.checkChange();
},
5. 页面中使用,监听vuex中数据变化,切换当前页面列数组。
watch: {
userDefined: {
handler() {
const data = this.userDefined.find((item) =>
item.path == "/order/refund"
);
this.userDefinedObj = data?data.list:[];
},
immediate: true,
},
},
6. 表格的列,就是循环数组,赋值。
<el-table-column
v-for="item in userDefinedObj.filter((item) => item.isShow)" //过滤需要展示的字段。
:key="item.prop"
:label="item.label"
:align="item.align"
:fixed="item.fixed"
:width="item.width"
:formatter="methodsList[item.formatter]" //表格列内容格式化方法,数组中存的是方法名。
:prop="item.prop"
></el-table-column>
7. methodsList是存的格式化列内容的方法,这个方法之所以写在页面中,而不是跟其他的一样放全局数组中,是因为我所有的字段配置都是存localstrage中的,需要JSON.stringify(),但是这个方法没办法保存方法,只能保存方法名,方法还是放在页面组件中。
methodsList: {
formatRefundStatus(row, column, cellValue, index) {
return cellValue == 1 ? "无" : cellValue == 2 ? "有" : "";
},
...省略,
formatTime(row, column, cellValue, index) {
let time = new Date(cellValue);
let y = time.getFullYear();
let m = time.getMonth() + 1;
let d = time.getDate();
let h = time.getHours();
let mm = time.getMinutes();
let s = time.getSeconds();
const value =
y +
"-" +
(m < 10 ? "0" + m : m) +
"-" +
(d < 10 ? "0" + d : d) +
" " +
(h < 10 ? "0" + h : h) +
":" +
(mm < 10 ? "0" + mm : mm) +
":" +
(s < 10 ? "0" + s : s);
return cellValue ? value : "暂无";
},
},
8. 这个表格字段过滤,只能存一些简单的,固定的内容,但是大家都知道el-table是带有slot的,如果是用slot,就需要改一下。
第一步:和formatter参数一样,增加一个slot字段。
{
label: "订单编号",
align: "center",
width: "190",
prop: "orderSn",
isShow: true,
hasSlot: true,
slot: "orderSlot",
},
第二步:现在有需要用slot和不需要用的,增加一个判断,把scope传到slotList对象中对应的方法,返回需要渲染的html字符串,然后用v-html指令渲染。
<el-table-column
v-for="item in userDefinedObj.filter((item) => item.isShow)"
:key="item.prop"
:label="item.label"
:align="item.align"
:fixed="item.fixed"
:width="item.width"
:formatter="methodsList[item.formatter]"
:prop="item.prop"
>
<template slot-scope="scope">
<div v-if="item.hasSlot" v-html="slotList[item.slot](scope)"></div>
<div v-else>{{ scope.row[item.prop] }}</div>
</template>
</el-table-column>
</el-table>
slotList对象和methodsList差不多,格式如下:
slotList: {
orderSlot: (scope) => {
return `<div :class="${scope.row.groupPurchaseId} ? 'label_box' : ''">
<span>${scope.row.orderSn}</span>
</div>`;
},
}