效果图如下:
// 树配置项
defaultProps: {
children: 'children',
label: 'label',
disabled: "disabled"
}
<el-tree
ref="tree"
node-key="id"
:data="treeData"
:props="defaultProps"
:show-checkbox="true"
:default-expand-all="true"
:expand-on-click-node="false"
:highlight-current="true"
empty-text=""
@node-click="handleNodeClick"
@check="handleCheckboxClick">
<slot class="custom-tree-node" v-slot="{ node, data }">
<span>{{ node.label }}</span>
</slot>
</el-tree>
<el-table ref="multipleTable"
:data="tableData"
:cell-style="row"
:header-cell-style="header"
tooltip-effect="light"
@select="handleSelectionChange"
@select-all="handleSelectionAllChange">
<el-table-column type='selection' />
<template v-for="(i, index) in tableOptions">
<el-table-column :key="index" :prop="i.prop" :label="i.label" :width="i.width" :show-overflow-tooltip="true">
<template v-slot="scope">
<div v-html="formatValue(i.prop, scope.row)"></div>
</template>
</el-table-column>
</template>
</el-table>
// 选中树节点事件
handleNodeClick(row) {
if (!row.id || this.queryParams.parentId === row.id) {
return
}
this.queryParams.pageNum = 1;
this.queryParams.parentId = row.id;
this.getRegionInfoById();
}
// 选中树节点查询事件
async getRegionInfoById () {
this.loading = true;
const res = await getRegionByInfo( this.queryParams );
if ( res.code !== 200 ) {
return
}
this.total = res.data.data.total;
this.tableData = res.data.data.list;
this.queryParams.superiorsId = res.data.superiorsId;
this.queryParams.juniorsId = res.data.juniorsId;
this.loading = false;
this.$nextTick(this.toggleSelection);
}
// 操作分页表格勾选状态
toggleSelection() {
this.tableData.forEach(row => {
// 如果当前id不存在于集合中 (例如:我选择其他目录数据 选中当前目录没选择数据 初始化状态)
if (!this.checkedNodes.has(row.parentId)) {
this.$refs.multipleTable.clearSelection();
return
}
const nodes = this.checkedNodes.get(row.parentId);
// 代表全选
if (nodes.isCheckAll && !nodes.check.length && !nodes.del.length) {
this.$refs.multipleTable.toggleRowSelection(row, true);
return
}
// 代表单选
if (nodes.check.length && nodes.check.includes(row.regionId)) {
this.$refs.multipleTable.toggleRowSelection(row, true);
return
}
// 代表全选后单选取消
if (nodes.del.length && !nodes.del.includes(row.regionId)) {
this.$refs.multipleTable.toggleRowSelection(row, true);
return
}
this.$refs.multipleTable.toggleRowSelection(row, false);
})
}
// 全选树形事件
handleCheckboxClick(node, data) {
if (!node.size) {
return
}
// 如果row中没有children 表示是子节点 允许set到map中
if (!node.children) {
this.checkedNodes.set(node.id, { isCheckAll: true, check: [], del: [] });
} else {
const ds = (array) => {
if (!!array.children) {
ds(array.children);
return
}
if (Object.prototype.toString.call(array) === '[object Object]') {
this.checkedNodes.set(array.id, { isCheckAll: true, check: [], del: [] });
}
if (Object.prototype.toString.call(array) === '[object Array]') {
array.forEach(row => this.checkedNodes.set(row.id, { isCheckAll: true, check: [], del: [] }));
}
}
node.children.forEach(ds)
}
// 将map集合所有key在data.checkedKeys中对比 如果不存在 代表取消勾选 在map中删除掉取消的key
const differentElements = Array.from(this.checkedNodes.keys()).filter(element => !data.checkedKeys.includes(element));
differentElements.forEach(element => this.checkedNodes.delete(element));
// 是否在父子节点中存在
if (this.queryParams.superiorsId.includes(node.id) || this.queryParams.juniorsId.includes(node.id)) {
this.$nextTick(this.toggleSelection);
}
}
// 单选表格数据
async handleSelectionChange(selection, row) {
if (!row.parentId || !row.regionId) {
return
}
// 声明变量获取储存后的map集合
const selectRegionIdArr = this.checkedNodes;
// 如果集合不存在当前 key 就初始化一个
if (!selectRegionIdArr.has(row.parentId)) {
selectRegionIdArr.set(row.parentId, { isCheckAll: false, check: [], del: [] });
}
// 集合中找到当前文件夹的 values
const values = selectRegionIdArr.get(row.parentId);
// 判断选中的人员中是否存在重复的
const checkIndex = values.check.indexOf(row.regionId);
const delIndex = values.del.indexOf(row.regionId);
// 执行单选以及取消单选操作
!values.isCheckAll ? checkIndex < 0 ? values.check.push(row.regionId) : values.check.splice(checkIndex, 1)
: delIndex < 0 ? values.del.push(row.regionId) : values.del.splice(delIndex, 1);
const nodes = this.$refs.tree.getNode(row.parentId);
await this.updateTreeDataSelection(nodes, values);
}
// 全选表格当前页数据
handleSelectionAllChange(selection) {
if (!!selection.length) {
selection.forEach(row => this.updateNodeState(row, true));
} else {
this.tableData.forEach(row => this.updateNodeState(row, false));
}
},
async updateNodeState(row, b) {
const treeInstance = this.$refs.tree; // 获取 el-tree 实例
const checkNodes = this.checkedNodes; // 获取 map 集合
if (!checkNodes.has(row.parentId)) {
checkNodes.set(row.parentId, { isCheckAll: false, check: [], del: [] });
}
const values = checkNodes.get(row.parentId);
if (values) {
// 判断选中的点位中是否存在重复的
const checkIndex = values.check.indexOf(row.regionId);
const delIndex = values.del.indexOf(row.regionId);
if (!values.isCheckAll) {
// 单选 全选当前页
if (checkIndex < 0 && b) {
values.check.push(row.regionId);
}
if (checkIndex >= 0 && !b) {
values.check.splice(checkIndex, 1);
}
} else {
// 全选 全选当前页
if (delIndex >= 0 && b) {
values.del.splice(delIndex, 1);
}
if (delIndex < 0 && !b) {
values.del.push(row.regionId);
}
}
}
const nodes = treeInstance.getNode(row.parentId);
await this.updateTreeDataSelection(nodes, values);
}
// 操作树结构勾选状态以及改变集合状态
updateTreeDataSelection(nodes, values) {
// 代表该目录是全选状态
if (!values.check.length && !values.del.length && values.isCheckAll) {
// 给与当前节点在树中的勾选状态
this.$refs.tree.setChecked(nodes, true);
// 当前节点在树的勾选状态
// nodes.checked = true;
// 当前节点在树的的不明确状态
nodes.indeterminate = false;
// 当前节点在集合中勾选状态
values.isCheckAll = true;
return
}
// 代表该目录没有任何勾选状态
if (!values.check.length && !values.del.length && !values.isCheckAll) {
// 给与当前节点在树中的勾选状态
this.$refs.tree.setChecked(nodes, false);
// 当前节点在树的勾选状态
// nodes.checked = false;
// 当前节点在树的的不明确状态
nodes.indeterminate = false;
// 当前节点在集合中勾选状态
values.isCheckAll = false;
return
}
// 代表该目录是全选状态
if (values.check.length === nodes.data.size && !values.del.length) {
// 给与当前节点在树中的勾选状态
this.$refs.tree.setChecked(nodes, true);
// 当前节点在树的勾选状态
// nodes.checked = true;
// 当前节点在树的的不明确状态
nodes.indeterminate = false;
// 当前节点在集合中勾选状态
values.isCheckAll = true;
// 清空当前节点在集合中的选中数组
values.check.splice(0);
return
}
// 代表该目录是半选状态
if (values.check.length < nodes.data.size && !values.del.length) {
// 给与当前节点在树中的勾选状态
this.$refs.tree.setChecked(nodes, true);
// 当前节点在树的勾选状态
nodes.checked = true;
// 当前节点在树的的不明确状态
nodes.indeterminate = true;
// 当前节点在集合中勾选状态
values.isCheckAll = false;
return
}
// 代表该目录是全选后单选取消状态
if (values.del.length === nodes.data.size && !values.check.length) {
// 给与当前节点在树中的勾选状态
this.$refs.tree.setChecked(nodes, false);
// 当前节点在树的勾选状态
// nodes.checked = false;
// 当前节点在树的的不明确状态
nodes.indeterminate = false;
// 当前节点在集合中勾选状态
values.isCheckAll = false;
// 清空当前节点在集合中的选中数组
values.del.splice(0);
return
}
// 代表该目录是全选后单选取消完
if (values.del.length < nodes.data.size && !values.check.length) {
// 给与当前节点在树中的勾选状态
this.$refs.tree.setChecked(nodes, true);
// 当前节点在树的勾选状态
nodes.checked = true;
// 当前节点在树的的不明确状态
nodes.indeterminate = true;
// 当前节点在集合中勾选状态
values.isCheckAll = true;
}
}
map集合 key是存在children的区域id
全选区域下面所有的数据 那么 check 以及 del都是为空
全选数据后 单选取消 check为空 del不为空
单选数据 check不为空 del为空
有错误的地方 请大佬指教