前言
中后台项目中菜单功能(权限管理)页总是必不可少的, 而仅使用element中el-table组件的树形表格并不能很好的满足对应的业务需求,所以,就想到了使用el-checkbox来替代列表第一列的选框,之后由函数控制对应的选中事件。写的或许不是很完善,还请各位大佬多指教啦!
实现结果
话不多说,来看代码吧!
页面代码
<el-table
border
:data="tableData"
row-key="id"
default-expand-all
@select-all="chooseAll"
>
<!-- 这里用了el-table的select-all事件控制全选和反选 -->
<el-table-column
type="selection"
width="55"
align="center"
fixed="left"
>
<template slot-scope="{ row }">
<!-- 用el-checkbox替代原本的选框 -->
<!-- indeterminate属性控制选框的部分选中状态 -->
<el-checkbox
v-model="row.check"
:indeterminate="row.inType"
@change="chooseBlock(row)"
></el-checkbox>
</template>
</el-table-column>
<el-table-column
show-overflow-tooltip
prop="title"
label="菜单名称"
width="180"
fixed="left"
></el-table-column>
<el-table-column label="功能操作">
<template slot-scope="{ row }">
<!-- 这里是根据数据渲染的功能项 -->
<el-checkbox-group v-model="row.actives">
<el-checkbox
v-for="item in row.actionList"
:key="item.id"
:label="item.actionName"
@change="chooseActive(row)"
>{{ item.title }}</el-checkbox
>
</el-checkbox-group>
</template>
</el-table-column>
</el-table>
</el-card>
复制代码
数据格式
data() {
return {
tableData: [
{
title: "菜单1",
id: 1,
// pid 父级id 一级菜单为0
// 方便之后处理数据时遍历数组
pid: 0,
// 控制每行第一列选框的选中状态
check: false,
inType: false,
// 菜单对应的功能列表
actionList: [
{
id: 0,
actionName: "show",
title: "展示",
},
],
// 已选中(以保存)的菜单功能
actives: [],
// 下级菜单
children: [],
},
],
};
},
复制代码
对应的事件函数
methods: {
// 表格全选
chooseAll(val) {
// 需要递归处理数据
if (val.length > 0) {
// 大于0说明是选中状态
this.handleAll(true, this.tableData);
} else {
// 取消全选
this.handleAll(false, this.tableData);
}
},
// 选中/取消所有选项
handleAll(bol, list) {
list.forEach((ele) => {
// checkbox赋值
ele.check = bol;
// 重置部分选中状态
ele.inType = false;
if (ele.children && ele.children.length > 0) {
// 判断children存在且不为空, 则当前对象没有功能选项, 遍历children
this.handleAll(bol, ele.children);
} else {
// 当前对象存在选项
// 清空已选
ele.actives = [];
// bol = true则全选 为false什么都不做
if (bol) {
ele.actionList.forEach((item) => {
ele.actives.push(item.actionName);
});
}
}
});
},
// 左侧选框选中
chooseBlock(obj) {
// 选中时就不存在部分选中了,清除部分选中状态
obj.inType = false;
if (obj.actionList.length > 0) {
// 数组长度大于0, 存在对应的选项, 处理数据
// 清空选中数据
obj.actives = [];
// 判断选中状态 true:全选 false:取消
if (obj.check) {
// 全选 遍历选项列表
obj.actionList.forEach((ele) => {
obj.actives.push(ele.actionName);
});
}
// 更新菜单选中状态
this.inspectRow(obj.pid, this.tableData);
} else {
// 判断children是否为空或不存在
if (obj.children && obj.children.length > 0) {
if (obj.check) {
this.handleAll(true, obj.children);
} else {
this.handleAll(false, obj.children);
}
}
}
},
// 选中功能选项
chooseActive(obj){
// actives.length不为0说明有选中的项
if(obj.actives.length != 0){
if(obj.actives.length < obj.actionList.length){
// 已选数量小于选项数量, 未全选, 菜单选框部分选中
obj.inType = true;
obj.check = false;
} else {
// 已选数量等于选项数量, 全选, 菜单选框选中
obj.inType = false;
obj.check = true;
};
} else {
// actives.length == 0 没有选中, 取消选框状态
obj.check = false;
obj.inType = false;
};
// 更新菜单选中状态
this.inspectRow(obj.pid, this.tableData);
},
// 选中功能选项, 更新菜单行选中状态
inspectRow(pid, list){
// 根据pid遍历数组
if(pid != 0){
// pid不为0 不为一级菜单
// 遍历数组 寻找对应项
let mobj = {};
list.forEach(ele => {
if(ele.id == pid){
// 符合条件, 暂存
mobj = ele;
}
});
if(mobj.id){
// 已找到对应pid的对象
let listNum = mobj.children.length;
let checkNum = 0;
let inTypeNum = 0;
// 遍历数组, 获取已全选和部分选中的对象数量
mobj.children.forEach(ele => {
ele.check == true ? checkNum++ : "";
ele.inType == true ? inTypeNum++ : "";
});
if(checkNum == listNum){
// 已全选数量和数组数量一致, 全选状态
mobj.check = true;
mobj.inType = false;
} else if(checkNum < listNum && checkNum > 0){
// 存在部分子对象全选, 父对象显示部分选中状态
mobj.check = false;
mobj.inType = true;
} else if(inTypeNum > 0){
// 没有全选状态的子对象, 但存在部分选中的子对象
// 父对象显示部分选中状态
mobj.check = false;
mobj.inType = true;
} else {
// 子对象无选中
mobj.check = false;
mobj.inType = false;
};
// pid不为0 代表还有父级对象, 递归改变父级选框状态
if(mobj.pid != 0){
this.inspectRow(mobj.pid, this.tableData);
}
} else {
// 当前数据层未找到符合条件的对象, 寻找下一层
list.forEach(ele => {
if(ele.children && ele.children.length > 0){
this.inspectRow(pid, ele.children);
}
});
}
}
}
},
复制代码
遗留问题
如图所示,表头的选框只有控制全选/反选的功能,在数据展示上无法显示对应的部分选中状态,没有像下边的数据部分一样很好的联动展示,算是一点瑕疵吧。如果有更好的方法或者思路,还请多多指教!(在此拜各位大佬)
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END