问题:vue2项目,实现四层checkbox嵌套联动;

<template>
<div id="app">
<div class="topCheckbox">
<div
v-for="(timeSheetItem, index) in timeSheetInfoData"
:key="index"
class="oneFloor"
>
<div class="oneTitle">
<van-checkbox
v-model="timeSheetItem.checked"
:name="`${timeSheetItem.evaIds}${index}`"
class="titleLift"
icon-size="18px"
@click="oneCheckboxClick(index, timeSheetItem)"
>
{{ timeSheetItem.userName }} {{ timeSheetItem.period }}
{{ timeSheetItem.totalHour }}h
</van-checkbox>
<div class="titleRight" @click="oneFloorClick(timeSheetItem, index)">
<span>{{ timeSheetItem.unflod % 2 === 0 ? "折叠" : "展开" }}</span>
<div>
<van-icon
v-if="timeSheetItem.unflod % 2 === 0"
name="arrow-up"
size="16px"
></van-icon>
<van-icon v-else name="arrow-down" size="16px"></van-icon>
</div>
</div>
</div>
<template v-if="timeSheetItem.unflod % 2 === 0">
<div
v-for="(itemSecond, indexSecond) in restList[index]"
:key="indexSecond"
class="twoFloor"
>
<div class="twoTitle">
<van-checkbox
v-model="itemSecond.checked"
:name="`${itemSecond.evaIds}${index}`"
class="titleLift"
icon-size="15px"
@click="
twoCheckboxClick(
index,
itemSecond,
timeSheetItem,
indexSecond
)
"
>
{{ itemSecond.reportDate }} {{ itemSecond.week }}
{{ itemSecond.hour }}h
</van-checkbox>
<div
class="titleRight"
@click="twoFloorClick(itemSecond, index, indexSecond)"
>
<span>{{ itemSecond.unflod % 2 === 0 ? "折叠" : "展开" }}</span>
<div>
<van-icon
v-if="itemSecond.unflod % 2 === 0"
name="arrow-up"
></van-icon>
<van-icon v-else name="arrow-down"></van-icon>
</div>
</div>
</div>
<template v-if="itemSecond.unflod % 2 === 0">
<div
v-for="(itemThird, indexThird) in itemSecond.list"
:key="indexThird"
class="threeFloor"
>
<van-checkbox
ref="checkboxThird"
v-model="itemThird.ckecked"
class="left"
:name="`${itemThird.evaIds}`"
icon-size="15px"
@click="checkboxClickThree(index, itemSecond)"
></van-checkbox>
<div class="right">
<div class="date">
{{ itemThird.taskName }}
</div>
</div>
</div>
</template>
</div>
</template>
</div>
</div>
<van-checkbox v-model="isCheckAll" @click="checkAll">全选</van-checkbox>
</div>
</template>
<script>
// import Vue from 'vue'
import mockData from '../src/assets/util/js/mock'
export default {
name: 'FourFloorCheckbox',
data () {
return {
timeSheetInfoData: [],
restList: [],
isCheckAll: false
}
},
created () {
this.loadFirstList()
},
methods: {
// 获取第一层数据
loadFirstList () {
setTimeout(() => {
this.timeSheetInfoData = mockData.firstFloorData
}, 200)
},
// 全选
checkAll () {
if (this.isCheckAll) {
this.timeSheetInfoData.map((item) => {
console.log(11)
item.checked = true
return item
})
} else {
this.timeSheetInfoData.map((item) => {
item.checked = false
return item
})
}
},
// 点击第一层复选框
oneCheckboxClick (index, item) {
console.log('change1', item.checked, item.unflod)
// this.$forceUpdate()
// 与全选按钮的关系
const allChecked = this.timeSheetInfoData.every(item => item.checked === true)
const someChecked = this.timeSheetInfoData.some(item => item.checked === false)
if (allChecked) {
this.isCheckAll = true
}
if (someChecked) {
this.isCheckAll = false
}
if (item.unflod !== 1) {
this.$forceUpdate()
if (item.checked) {
this.restList[index].map((item) => {
item.checked = true
return item
})
} else {
this.restList[index].map(item => {
item.checked = false
return item
})
}
}
},
// 点击第一层展开/折叠 展开-发送接口拿剩余数据
oneFloorClick (timeSheetItem, index) {
// 第一次单击 展开 调接口
if (timeSheetItem.unflod === 1) {
this.loadRestList(timeSheetItem, index)
} else {
timeSheetItem.unflod++
}
this.$forceUpdate()
},
// 获取第二层及第三层的数据
loadRestList (timeSheetItem, index) {
setTimeout((item) => {
console.log('调接口拿到数据')
this.$set(this.restList, index, mockData.restData)
if (timeSheetItem.checked) {
this.restList[index].map(item => {
item.checked = true
return item
})
} else {
this.restList[index].map(item => {
item.checked = false
return item
})
}
timeSheetItem.unflod++ // 展开折叠板
}, 200)
},
// 点击第二层复选框
twoCheckboxClick (index, itemSecond, timeSheetItem, indexSecond) {
console.log(2222, itemSecond.checked)
// 与第一层的关系
const allChecked = this.restList[index].every(item => item.checked === true)
const someChecked = this.restList[index].some(item => item.checked === false)
if (allChecked) {
timeSheetItem.checked = true
}
if (someChecked) {
timeSheetItem.checked = false
}
},
// 点击第二层展开/折叠
twoFloorClick (itemSecond, index, indexSecond) {
itemSecond.unflod++
this.$forceUpdate()
if (itemSecond.checked) {
console.log(2223)
itemSecond.list.map((item) => {
item.checked = true
return item
})
// itemSecond.list.map((item) => { this.$set(item, 'checked', true) })
// this.restList[index][indexSecond].list.forEach((val, indx) => {
// this.$set(this.restList[index][indexSecond].list[indx], 'checked', true)
// })
} else {
console.log(2224)
itemSecond.list.map((item) => {
item.checked = false
return item
})
// itemSecond.list.map((item) => { this.$set(item, 'checked', false) })
// this.restList[index][indexSecond].list.forEach((val, indx) => {
// this.$set(this.restList[index][indexSecond].list[indx], 'checked', false)
// })
}
},
// 点击第三层复选框
checkboxClickThree (index, itemSecond) {
this.$forceUpdate()
// 与第二层的关系
const allChecked = itemSecond.list.every(item => item.checked === true)
const someChecked = itemSecond.list.some(item => item.checked === false)
if (allChecked) {
itemSecond.checked = true
}
if (someChecked) {
itemSecond.checked = false
}
},
// 测试按钮点击
testClick () {
console.log('timeSheetData', this.timeSheetInfoData)
console.log('restList', this.restList)
}
}
}
</script>
<style lang="less">
.oneTitle {
display: flex;
justify-content: space-between;
padding: 20px 15px;
border-bottom: 1px solid #2c3e50;
.titleRight {
display: flex;
justify-content: flex-end;
}
}
.twoFloor {
padding: 15px 10px;
.twoTitle {
display: flex;
justify-content: space-between;
.titleLift {
padding-left: 20px;
}
}
.titleRight {
display: flex;
// justify-content: flex-end;
}
}
.threeFloor {
display: flex;
justify-content: space-between;
padding: 10px;
.left {
padding-left: 30px;
}
}
.topCheckbox {
padding-bottom: 50px;
}
</style>
下面是模拟的后台数据:
const mockData = {}
mockData.firstFloorData = [
{
checked: false,
evaIds: '450162,450163,450164,450165,450172,450173,450174,450175,450176,450177,450179,450180,450181,450274,450275',
month: '0',
period: '2023年01月',
totalHour: '112',
unflod: 1,
userId: 1383,
userName: '范令令',
week: null,
year: '2023'
},
{
checked: false,
evaIds: '450162,450163,450164,450165,450172,450173,450174',
month: '0',
period: '2023年08月',
totalHour: '224',
unflod: 1,
userId: 1383,
userName: '张三',
week: null,
year: '2023'
},
{
checked: false,
evaIds: '450162',
month: '0',
period: '2025年09月',
totalHour: '189',
unflod: 1,
userId: 1383,
userName: '李斯',
week: null,
year: '2023'
}
]
mockData.restData = [
{
checked: false,
evaIds: '450274',
hour: '8.0',
reportDate: '2023-01-30',
unflod: 1,
week: '周一',
list: [
{
checked: false,
comment: '',
taskName: '学习歌单听得有点难过',
taskSource: '部门日常任务',
unflod: 1,
week: '周一'
},
{
checked: false,
comment: '',
taskName: '人要往前走,就要换歌单,以前的歌单太重了',
taskSource: '部门日常任务',
unflod: 1,
week: '周一'
}
]
},
{
checked: false,
evaIds: '450274',
hour: '8.0',
reportDate: '2023-01-30',
unflod: 1,
week: '周一',
list: [
{
checked: false,
comment: '',
taskName: '学习歌单听得有点难过',
taskSource: '部门日常任务',
unflod: 1,
week: '周一'
},
{
checked: false,
comment: '',
taskName: '人要往前走,就要换歌单,以前的歌单太重了',
taskSource: '部门日常任务',
unflod: 1,
week: '周一'
}
]
}
]
export default mockData
由于数据起初不是响应式,加上我思维混乱,搞晕了。