通过elementui的树形table组件,实现多级联动效果
效果截图

element 版本 element-ui": "2.13.2
主要思想 递归
vue页面 包括数据结构 js
<template>
<div class="tree-table-wrapper">
<el-table
:data="tableData"
style="width: 100%;margin-bottom: 20px;"
row-key="id"
border
:tree-props="{children: 'children', hasChildren: 'hasChildren'}"
>
<el-table-column prop="name" label="页面" width="180">
<template slot-scope="props">
<el-checkbox
v-model="props.row.isChecked"
:indeterminate="props.row.indeterminate"
@change="checkboxChange(props.row)"
/>
{{ props.row.name }}
{{ props.row.isChecked }}
</template>
</el-table-column>
<el-table-column prop="authList" label="权限">
<template slot-scope="props">
<div class="auth-checkbox">
<div v-for="(item, i) in props.row.authList" :key="i">
<el-checkbox
v-model="item.isChecked"
@change="checkboxChangeRight(props.row, item)"
></el-checkbox>
{{item.name}}{{item.isChecked}}
</div>
</div>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script>
export default {
name: 'TreeTable',
data() {
return {
tableData: [
{
id: 1,
date: '2016-05-02',
name: '王小虎1',
address: '上海市普陀区金沙江路 1518 弄',
isChecked: false,
indeterminate: false,
authList: [
{
id: 101,
pid: 1,
date: '2016-05-02',
name: '页面1',
address: '上海市普陀区金沙江路 1518 弄',
isChecked: false
},
{
id: 102,
pic: 1,
date: '2016-05-02',
name: '页面2',
address: '上海市普陀区金沙江路 1518 弄',
isChecked: false
}
]
},
{
id: 2,
date: '2016-05-04',
name: '王小虎1',
address: '上海市普陀区金沙江路 1517 弄',
isChecked: false,
indeterminate: false,
authList: [
{
id: 201,
pid: 2,
date: '2016-05-02',
name: '页面1',
address: '上海市普陀区金沙江路 1518 弄',
isChecked: false
},
{
id: 201,
pid: 2,
date: '2016-05-02',
name: '页面2',
address: '上海市普陀区金沙江路 1518 弄',
isChecked: false
}
]
},
{
id: 3,
date: '2016-05-01',
name: '王小虎1',
address: '上海市普陀区金沙江路 1519 弄',
isChecked: false,
indeterminate: false,
authList: [
{
id: 301,
pid: 3,
date: '2016-05-02',
name: '页面1',
address: '上海市普陀区金沙江路 1518 弄',
isChecked: false
},
{
id: 302,
pid: 3,
date: '2016-05-02',
name: '页面2',
address: '上海市普陀区金沙江路 1518 弄',
isChecked: false
}
],
children: [
{
pid: 3,
id: 31,
date: '2016-05-01',
name: '王小虎2',
address: '上海市普陀区金沙江路 1519 弄',
isChecked: false,
indeterminate: false,
authList: [
{
id: 3101,
pid: 31,
date: '2016-05-02',
name: '页面1',
address: '上海市普陀区金沙江路 1518 弄',
isChecked: false
},
{
id: 3102,
pid: 31,
date: '2016-05-02',
name: '页面2',
address: '上海市普陀区金沙江路 1518 弄',
isChecked: false
}
]
},
{
pid: 3,
id: 32,
date: '2016-05-01',
name: '王小虎2',
address: '上海市普陀区金沙江路 1519 弄',
isChecked: false,
indeterminate: false,
authList: [
{
id: 3201,
pid: 32,
date: '2016-05-02',
name: '页面1',
address: '上海市普陀区金沙江路 1518 弄',
isChecked: false
},
{
id: 3202,
pid: 32,
date: '2016-05-02',
name: '页面2',
address: '上海市普陀区金沙江路 1518 弄',
isChecked: false
}
],
children: [
{
pid: 32,
id: 321,
date: '2016-05-01',
name: '王小虎3',
address: '上海市普陀区金沙江路 1519 弄',
isChecked: false,
indeterminate: false,
authList: [
{
id: 32101,
pid: 321,
date: '2016-05-02',
name: '页面1',
address: '上海市普陀区金沙江路 1518 弄',
isChecked: false
},
{
id: 32102,
pid: 321,
date: '2016-05-02',
name: '页面2',
address: '上海市普陀区金沙江路 1518 弄',
isChecked: false
}
]
},
{
pid: 32,
id: 322,
date: '2016-05-01',
name: '王小虎3',
address: '上海市普陀区金沙江路 1519 弄',
isChecked: false,
indeterminate: false,
authList: [
{
id: 1,
date: '2016-05-02',
name: '页面1',
address: '上海市普陀区金沙江路 1518 弄',
isChecked: false
},
{
id: 1,
date: '2016-05-02',
name: '页面2',
address: '上海市普陀区金沙江路 1518 弄',
isChecked: false
}
]
}
]
}
]
},
{
id: 4,
date: '2016-05-03',
name: '王小虎1',
address: '上海市普陀区金沙江路 1516 弄',
isChecked: false,
indeterminate: false,
authList: [
{
id: 1,
date: '2016-05-02',
name: '页面1',
address: '上海市普陀区金沙江路 1518 弄',
isChecked: false
},
{
id: 1,
date: '2016-05-02',
name: '页面2',
address: '上海市普陀区金沙江路 1518 弄',
isChecked: false
}
]
}
]
}
},
methods: {
/**
* 左侧复选框 按钮点击事件
* @param {row: object} 当前选中的row数据
* */
checkboxChange(row) {
const self = this
// 当前checkbox状态
const isChecked = row.isChecked
/**
* 父级全选
* @param {row: object}
* 点击左侧checkbox 时 子级所有选项选中或取消 -- 包括右侧checkbox
* */
changeAll(row)
function changeAll(rowData) {
// rowData.indeterminate = false
// 改变checkbox状态
rowData.isChecked = isChecked
// 改变右侧表格中的checkbox
rowData.authList &&
rowData.authList.forEach(authItem => {
authItem.isChecked = isChecked
})
if (rowData.children) {
rowData.children.forEach(element => {
// element.indeterminate = false
// element.isChecked = isChecked
// element.authList.forEach(authItem => {
// authItem.isChecked = isChecked
// })
// if (element.children) {
// changeAll(element)
// }
// 递归处理数据
changeAll(element)
})
}
}
/**
* 子级选择
* @param {row: object}
* 点击子级选项 选中子级右侧数据 同时递归选中父级以及祖级
* */
changeParents(row)
function changeParents(rowData) {
// 所有数据
const allData = self.tableData
// 当前选择的pid
const pid = rowData.pid
findParent(allData, pid)
// 递归处理
function findParent(element, pid) {
element.forEach(item => {
if (item.id == pid) {
if (isChecked) {
// 选中状态为true
// item.indeterminate = true
item.isChecked = true
// 递归处理父级状态
const pid = item.pid
findParent(allData, pid)
} else {
changeLeftParent(self.tableData, row.pid)
}
} else {
if (item.children) {
findParent(item.children, pid)
}
}
})
}
}
// 处理左侧取消checkbox状态
function changeLeftParent(element, pid) {
element.forEach(item => {
const checkList = []
if (item.id == pid) {
if (item.children) {
item.children.forEach(citem => {
checkList.push(citem.isChecked)
citem.authList.forEach(cauthItem => {
checkList.push(cauthItem.isChecked)
})
})
}
item.authList.forEach(cauthItem => {
checkList.push(cauthItem.isChecked)
})
if (!checkList.includes(true)) {
item.isChecked = false
changeLeftParent(self.tableData, item.pid)
}
} else {
if (item.children) {
changeLeftParent(item.children, pid)
}
}
})
}
},
// checkbox right
checkboxChangeRight(row, item) {
const self = this
// 父级选择
const isChecked = item.isChecked
if (isChecked) {
// 状态为true
row.isChecked = true
} else {
// 状态为false
// ----------取消父级的选中状态-------------
const checkList = []
row.authList.forEach(authItem => {
checkList.push(authItem.isChecked)
})
if (!row.children) {
// 无子级
if (!checkList.includes(true)) {
row.isChecked = false
}
//
changeLeftParent(self.tableData, row.pid)
} else {
// 有子级
if (!checkList.includes(true)) {
const checkList = []
row.children.forEach(item => {
checkList.push(item.isChecked)
})
if (!checkList.includes(true)) {
row.isChecked = false
}
}
changeLeftParent(self.tableData, row.pid)
}
// ------------------------------------------
}
const allData = self.tableData
findParent(allData, row.pid)
// 递归处理
function findParent(element, pid) {
element.forEach(item => {
if (item.id == pid) {
if (isChecked) {
// 选中状态为true
// item.indeterminate = true
item.isChecked = true
// 递归处理父级状态
const pid = item.pid
findParent(allData, pid)
}
} else {
if (item.children) {
findParent(item.children, pid)
}
}
})
}
// 处理左侧取消checkbox状态
function changeLeftParent(element, pid) {
element.forEach(item => {
const checkList = []
if (item.id == pid) {
if (item.children) {
item.children.forEach(citem => {
checkList.push(citem.isChecked)
citem.authList.forEach(cauthItem => {
checkList.push(cauthItem.isChecked)
})
})
}
item.authList.forEach(cauthItem => {
checkList.push(cauthItem.isChecked)
})
if (!checkList.includes(true)) {
item.isChecked = false
changeLeftParent(self.tableData, item.pid)
}
} else {
if (item.children) {
changeLeftParent(item.children, pid)
}
}
})
}
}
}
}
</script>
<style lang="scss" scoped>
.auth-checkbox {
width: 100%;
// display: flex;
// flex-wrap: wrap;
display: grid;
grid-template-columns: repeat(10, 1fr);
div {
margin-right: 5px;
}
}
</style>