vue3 两级树列表,父节点可以展开收缩 可以全选和取消全选 子节点可以选中 子节点全部选择后父节点自动选择
可以按照以下步骤进行操作:
- 在Vue组件中,创建一个包含树的数据的数组,每个节点包含id、label、selected、expanded和children属性。
- 在模板中使用v-for指令循环渲染树的节点,并根据节点的属性绑定选择状态、展开状态和相应的事件处理程序。
- 实现展开收缩功能:为了实现节点的展开和收缩,你可以使用节点的expanded属性来表示节点是否展开。通过点击展开收缩的图标或按钮时,切换节点的expanded属性的值。
- 实现全选和取消全选功能:在父节点上添加一个复选框,用于全选和取消全选子节点。通过v-model指令将该复选框与全选状态绑定,并在变化时更新所有节点的选择状态。
- 实现子节点全部选择后父节点自动选择的行为:通过监听子节点选择状态的变化,在所有子节点都被选择时,自动将父节点的选择状态设置为选中。
下面是一个示例的代码片段,演示了如何在一个Vue组件中实现上述功能:
/**
* @Author: 858834013@qq.com
* @Name: item1
* @Date: 2023年06月28日14:30:09
* @Desc:
*/
<template>
<div class="container">
<div class="search">
<input type="text" placeholder="请选择设备">
<img src="./assets/icon_search.png" alt="">
</div>
<div class="tree">
<ul>
<li v-for="node in treeData" :key="node.id">
<div class="titleInfo">
<div class="zhankai" @click="toggleExpand(node)">
<img v-if="node.expanded" src="./assets/icon_zhankai.png" alt="">
<img v-else src="./assets/icon_shousuo.png" alt="">
</div>
<selected v-model:expanded="node.selected" @change="checkChildren(node)"></selected>
<div class="shexiangtou">
<img src="./assets/icon_shexiangtou.png" alt="">
</div>
<span @click="toggleExpand(node)">{{ node.label }}</span>
</div>
<ul v-show="node.expanded">
<li v-for="child in node.children" :key="child.id">
<div class="titleInfo">
<selected v-model:expanded="child.selected" @change="checkParent(node)"></selected>
<div class="shexiangtou">
<img src="./assets/icon_shexiangtou.png" alt="">
</div>
<span @click="child.selected=!child.selected">{{ child.label }}</span>
</div>
</li>
</ul>
</li>
</ul>
</div>
</div>
</template>
<script>
import selected from "./selected.vue";
export default {
name: 'item1s',
data() {
return {
treeData: [
{
id: 1,
label: 'Parent 1',
selected: false,
expanded: false,
children: [
{
id: 2,
label: 'Child 1-1',
selected: false
},
{
id: 3,
label: 'Child 1-2',
selected: false
}
]
}
]
};
},
components: {selected},
computed: {
selectAll: {
get() {
return this.treeData.every(node => node.selected);
},
set(value) {
this.treeData.forEach(node => {
node.selected = value;
});
}
}
},
methods: {
toggleExpand(parent) {
parent.expanded = !parent.expanded;
},
checkChildren(parent) {
parent.children.forEach(child => {
child.selected = parent.selected;
});
},
checkParent(parent) {
parent.selected = parent.children.every(child => child.selected);
},
selectAllNodes() {
if (this.selectAll) {
this.treeData.forEach(parent => {
parent.selected = false;
parent.children.forEach(child => {
child.selected = false;
});
});
} else {
this.treeData.forEach(parent => {
parent.selected = true;
parent.children.forEach(child => {
child.selected = true;
});
});
}
}
}
}
</script>
<style lang="scss" scoped>
.container {
width: calc(100% - 40px);
height: calc(100% - 40px);
position: relative;
margin: 0 auto;
.search {
width: 100%;
height: 38px;
background: url("./assets/searchbg.png") no-repeat;
background-size: 100% 100%;
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: nowrap;
flex-direction: row;
align-content: flex-start;
input {
background: none;
width: calc(100% - 12px);
outline: none;
border: none;
position: relative;
height: calc(100% - 3px);
color: #fff;
margin-left: 12px;
}
/* 标准写法 */
input::placeholder {
color: rgba(126, 175, 236, 1);
}
/* WebKit 内核浏览器(Chrome、Safari) */
input::-webkit-input-placeholder {
color: rgba(126, 175, 236, 1);
}
/* Internet Explorer 浏览器 */
input:-ms-input-placeholder {
color: rgba(126, 175, 236, 1);
}
img {
width: 16px;
height: 16px;
margin-right: 14px;
flex-shrink: 0;
}
}
}
.tree {
width: 100%;
position: relative;
height: calc(100% - 300px);
ul {
list-style-type: none;
font-size: 14px;
font-family: MiSans;
font-weight: 400;
color: #FFFFFF;
}
}
.titleInfo {
display: flex;
justify-content: flex-start;
align-items: center;
flex-wrap: nowrap;
flex-direction: row;
align-content: flex-start;
height: 45px;
cursor: pointer;
}
.shexiangtou {
width: 34px;
display: flex;
justify-content: center;
align-items: center;
flex-wrap: nowrap;
flex-direction: row;
align-content: flex-start;
img {
width: 14px;
}
}
.zhankai {
display: flex;
justify-content: flex-start;
align-items: center;
flex-wrap: nowrap;
flex-direction: row;
align-content: flex-start;
img {
margin-right: 10px;
}
}
</style>
在这个示例中,我们通过使用v-for指令循环渲染父节点和子节点,然后使用v-model指令实现选择状态的双向绑定。我们还添加了一些方法来处理展开、选择和全选的逻辑。最后,我们使用计算属性来获取全选状态,并在全选复选框上使用v-model指令实现全选和取消全选的功能。