两级联动组件使用(vue)🎈🎈🎈🎈
代码片段复制时 需要安装less预处理器 样式使用的是less
效果展示



代码片段
<template>
<div class="nextLevel">
<h2 class="nextLevel_h2">点击展示下一级</h2>
<div class="nextLevel_box">
<ul class="nextLevel_box_1">
<li
:class="{ activate: activateId === i.id }"
v-for="i in arr"
:key="i.id"
@click="addFn(i)"
>
<div
class="button"
:class="{ activate_btn: i.checked }"
@click.stop="btnFn(i)"
></div>
商品分类:{{ i.name }}
</li>
</ul>
<ul class="nextLevel_box_2" v-show="arr2.length">
<li v-for="i in arr2" :key="i.id">
<div
class="button"
@click.stop="btnFn2(i)"
:class="{ activate_btn: i.checked }"
></div>
商品/名称:{{ i.name }}
</li>
</ul>
</div>
</div>
</template>
<style lang="less" scoped>
@bacColor: aqua;
ul,
li,
ol {
margin: 0;
padding: 0;
list-style: none;
cursor: pointer;
}
li:hover {
background-color: @bacColor;
}
.nextLevel {
margin: 10% auto;
box-sizing: border-box;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
&_h2 {
color: red;
}
&_box {
width: 50%;
display: flex;
& > ul {
flex: 1;
background-color: pink;
li {
padding-left: 15px;
display: flex;
align-items: center;
&.activate {
background-color: @bacColor;
}
.button {
width: 16px;
height: 16px;
border: 1px solid #000;
border-radius: 50%;
margin-right: 5px;
margin-top: 2px;
&.activate_btn {
position: relative;
&::before {
position: absolute;
content: "✔";
line-height: 90%;
text-align: center;
color: #fff;
border-radius: 50%;
left: 50%;
top: 50%;
transform: translateX(-50%) translateY(-50%);
background-color: royalblue;
}
}
}
}
}
& > ul:nth-child(2) {
background-color: @bacColor;
}
}
}
</style>
<script>
export default {
name: "nextLevel",
data() {
return {
arr: [
{
id: "0",
name: "水果",
children: [
{
id: "01",
name: "苹果",
},
{
id: "02",
name: "香蕉",
},
],
checked: false,
},
{
id: "1",
name: "蔬菜",
children: [
{
id: "11",
name: "油麦菜",
},
{
id: "12",
name: "菠菜",
},
{
id: "13",
name: "花菜",
},
{
id: "14",
name: "白菜",
},
{
id: "15",
name: "红萝卜",
},
],
checked: false,
},
{
id: "2",
name: "刀具",
checked: false,
},
],
arr2: [],
activateId: "0",
arrVal: [],
echoObj: {
level1: ['0','1'],
level2: [],
},
};
},
methods: {
addFn(i) {
this.activateId = i.id;
if (Array.isArray(i.children)) {
this.arr2 = [...i.children];
} else {
this.arr2.length = 0;
this.activateId = "";
}
},
btnFn(i) {
this.arr = this.btnMapFn(this.arr, i.id, !i.checked);
const obj = this.arr.find((e) => e.id === i.id);
this.addFn(obj);
},
btnFn2(i) {
this.arr2 = this.btnMapFn(this.arr2, i.id, !i.checked);
let bl = this.arr2.every((e) => e.checked);
this.arr = this.btnMapFn(this.arr, i.id.substring(0, 1), bl, this.arr2);
},
getValFn() {
let arr2 = [];
let arr1 = this.arr
.map((e) => {
let valArr =
e?.children?.filter((e) => e.checked).map((e) => e.id) || [];
arr2 = [...arr2, ...valArr];
if (e.checked) {
return e.id;
}
})
.filter((e) => e);
this.arrVal = [...arr1, ...arr2];
this.echoObj.level1 = [...arr1];
this.echoObj.level2 = [...arr2];
},
btnMapFn(arr, id1, checked1, children1) {
return arr.map((e) => {
if (e.id === id1) {
return {
...e,
checked: checked1 ?? e.checked,
children:
children1 ||
e?.children?.map((v) => ({ ...v, checked: checked1 })),
};
} else {
return {
...e,
};
}
});
},
},
mounted() {
const { level1, level2 } = this.echoObj;
this.arr = this.arr.map((e) => {
const bl1 = Boolean(level1.filter((v) => v === e.id)[0]);
if (bl1) {
return {
...e,
checked: bl1,
children: e?.children?.map((v) => {
return {
...v,
checked: bl1,
};
}),
};
} else {
const arrFilter = e?.children?.map((v) => (Boolean(level2.filter((i) => i === v.id)[0])))
const bl2 = arrFilter?.findIndex(v => v === false) === -1
return {
...e,
checked: bl2,
children: e?.children?.map((v,i) => {
return {
...v,
checked: arrFilter[i],
};
}),
};
}
});
this.addFn(this.arr.find((e) => e.id === this.activateId));
},
watch: {
arr: {
deep: true,
handler() {
this.getValFn();
},
},
},
};
</script>
各位同行如果有更好的实现方案 评论一起交流加技术讨论 互相学习
动动发财的小手点赞加收藏💕💕💕💕