1.实现效果
2.数据和布局准备
准备一个 el-table 组件以及数据源,这里的数据源可以是你的接口提供的。
<template>
<div style="width: 78%;">
<el-table ref="menuTableRef" :data="menuList" style="width: 100%;margin-bottom: 20px;"
:row-class-name="rowClassNameFun" row-key="id" border
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }" @select="handleSelect"
@select-all="handleSelectAll">
<el-table-column type="selection" width="55"> </el-table-column>
<el-table-column align="center" prop="title" label="标题">
</el-table-column>
<el-table-column align="center" prop="describe" label="描述">
</el-table-column>
<el-table-column align="center" prop="name" label="name" />
</el-table>
</div>
</template>
<script>
export default {
name: 'MenuTree',
data() {
return {
menuList: [
{
id: 1,
title: '系统管理',
describe: '系统管理描述',
name: 'system',
parentId: 0,
children: [
{
id: 11,
title: '用户管理',
describe: '系统管理描述',
name: 'user',
parentId: 1,
children: []
},
{
id: 12,
title: '角色管理',
describe: '角色管理描述',
name: 'role',
parentId: 1,
children: []
}
]
},
{
id: 2,
title: '数据管理',
describe: '数据管理描述',
name: 'data',
parentId: 0,
children: [
{
id: 21,
title: '数据导入',
describe: '数据导入描述',
name: 'import',
parentId: 2,
children: []
}
]
},
{
id: 3,
title: '权限管理',
describe: '权限管理描述',
name: 'permission',
parentId: 0,
children: [
{
id: 31,
title: '角色管理',
describe: '角色管理描述',
name: 'role',
parentId: 3,
children: []
}
]
},
{
id: 4,
title: '日志管理',
describe: '日志管理描述',
name: 'log',
parentId: 0,
children: [
{
id: 41,
title: '操作日志',
describe: '操作日志描述',
name: 'operation',
parentId: 4,
children: []
}
]
},
{
id: 5,
title: '设置管理',
describe: '设置管理描述',
name: 'setting',
parentId: 0,
children: [
{
id: 51,
title: '参数设置',
describe: '参数设置描述',
name: 'parameter',
parentId: 5,
children: []
}
]
}
]
}
},
created() {
this.initData(this.menuList)
},
methods: {
initData(data) {
for (let item of data) {
item.isSelect = false // 默认为不选中
if (item.children && item.children.length > 0) {
this.initData(item.children)
}
}
}
}
3.代码实现
在每个方法中都写好了注释,细心看代码,一步一步跟着代码逻辑来就可以实现最终效果。
代码逻辑
表格数据是否选中标志
isSelect状态: true为选中状态; false为未选中状态; 空字符串为半选中状态
<script>
methods: {
initData(data) {
for (let item of data) {
item.isSelect = false // 默认为不选中
if (item.children && item.children.length > 0) {
this.initData(item.children)
}
}
},
rowClassNameFun({ row }) {
if (row.isSelect === "") {
return "indeterminate";
}
},
/**
* 处理选中事件
* @param selection 所有选中的row
* @param row 当前选中的row
*/
handleSelect(selection, row) {
//当点击父级点复选框时,当前的状态可能为未知状态,所以当前行状态设为false并选中,即可实现子级点全选效果
if (row.isSelect === "") {
row.isSelect = false;
this.$refs['menuTableRef'].toggleRowSelection(row, true);
}
row.isSelect = !row.isSelect
let level = this.getSelectedRowLevel(row)
if (level == 1) {
this.changeAllChildrenStatus(row.children, row.isSelect)
} else if (level == 2) {
this.changeAllChildrenStatus(row.children, row.isSelect)
this.changeAllParentsStatus(row)
} else if (level == 3) {
this.changeAllParentsStatus(row)
}
},
/**
* 处理全选事件
* @param selection 全选选中的行
*/
handleSelectAll(selection) {
let isAllSelect = this.checkIsAllSelect()
this.menuList.forEach((item) => {
item.isSelect = isAllSelect
this.$refs['menuTableRef'].toggleRowSelection(item, !isAllSelect)
this.handleSelect(selection, item)
})
},
/**
* 获取选中行的等级
* @param row
* @returns 1 父级 2 既是父级也是子级 3 叶子节点
*/
getSelectedRowLevel(row) {
if (row.parentId == 0) {
return 1
} else {
if (row.children || row.children.length) {
return 2
} else {
return 3
}
}
},
/**
* 改变所有子节点选中状态
* @param data
*/
changeAllChildrenStatus(data, isSelect) {
data.forEach((item) => {
item.isSelect = isSelect;
this.$refs['menuTableRef'].toggleRowSelection(item, isSelect);
if (item.children && item.children.length) {
this.changeAllChildrenStatus(item.children, isSelect);
}
})
},
/**
* 改变所有父级选中状态
* 操作的是子节点:
* 1、获取父节点
* 2、判断子节点选中个数,如果全部选中则父节点设为选中状态,如果都不选中,则为不选中状态,如果部分选择,则设为不明确状态
* 3、判断父节点是否还有父级
* @param row
*/
changeAllParentsStatus(row) {
let parentRow = null
if (row.parentId == 0) {
parentRow = row
} else {
parentRow = this.getParentRow(this.menuList, row.parentId)
}
let selectStatusList = []
this.getRowSelectStatus(parentRow.children, selectStatusList)
let isAllSelected = selectStatusList.every(e => e == true)
let isAllNotSelected = selectStatusList.every(e => e == false)
if (isAllSelected) {
parentRow.isSelect = true;
this.$refs['menuTableRef'].toggleRowSelection(parentRow, true);
} else if (isAllNotSelected) {
parentRow.isSelect = false;
this.$refs['menuTableRef'].toggleRowSelection(parentRow, false);
} else {
parentRow.isSelect = "";
}
// 还有父级
if (parentRow.parentId != 0) {
this.changeAllParentsStatus(parentRow)
}
},
/**
* 获取选中节点的根节点对象
* @param data
* @param parentId
*/
getParentRow(data, parentId) {
for (let item of data) {
if (item.id == parentId) {
return item;
}
if (item.children && item.children.length) {
let result = this.getParentRow(item.children, parentId);
if (result) {
return result;
}
}
}
return null;
},
/**
* 获取row选中状态
* @param data 行数据
* @param list 选中状态容器
*/
getRowSelectStatus(data, list) {
data.forEach((item) => {
list.push(item.isSelect)
if (item.children && item.children.length) {
this.getRowSelectStatus(item.children, list)
}
})
},
/**
* 判断一级row是否全选
* @returns
*/
checkIsAllSelect() {
let rootRowIsSelectList = []
this.menuList.forEach((item) => {
rootRowIsSelectList.push(item.isSelect);
});
//判断一级row是否是全选.如果一级row全为true,则设置为取消全选,否则全选
let isAllSelect = rootRowIsSelectList.every((item) => {
return true == item;
});
return isAllSelect;
},
/**
* 获取选中行的id列表
* @param data menuList
* @param list 选中row和被选中row父级id的列表
*/
getSelectedRowId(data, list) {
data.forEach((item) => {
if (item.isSelect || item.isSelect === "") {
list.push(item.id)
}
if (item.children && item.children.length) {
this.getSelectedRowId(item.children, list)
}
})
},
}
</script>
半选中样式
<style scoped lang="scss">
::v-deep .indeterminate .el-checkbox__input .el-checkbox__inner {
background-color: #409eff !important;
border-color: #409eff !important;
color: #fff !important;
}
::v-deep .indeterminate .el-checkbox__input.is-checked .el-checkbox__inner::after {
transform: scale(0.5);
}
::v-deep .indeterminate .el-checkbox__input .el-checkbox__inner {
background-color: #f2f6fc;
border-color: #dcdfe6;
}
::v-deep .indeterminate .el-checkbox__input .el-checkbox__inner::after {
border-color: #c0c4cc !important;
background-color: #c0c4cc;
}
::v-deep .product-show th .el-checkbox__inner {
display: none !important;
}
::v-deep .indeterminate .el-checkbox__input .el-checkbox__inner::after {
content: "";
position: absolute;
display: block;
background-color: #fff;
height: 2px;
transform: scale(0.5);
left: 0;
right: 0;
top: 5px;
width: auto !important;
}
::v-deep .product-show .el-checkbox__inner {
display: block !important;
}
::v-deep .product-show .el-checkbox {
display: block !important;
}
</style>
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。