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>
4.參考
- Element Table 表格樹形結構多選框選中父級時會選中子級(遞歸多級)_element table tree 選擇子級-CSDN博客
- less和scss樣式穿透的三種寫法_less deep寫法-CSDN博客