使用了ant-design的多选框组件和气泡组件。
1.数据格式
其中,val表示多选的框的值,selected表示该元素的city是否有选中的,也就是控制多选的样式,tag表示该多选框选中,如果是第一级则她的city的tag也全为true。show表示在页面中是否显示这个多选框~
2.html部分
1.图片
鼠标移入一级值的时候气泡组件会显示出对应city的值
2.代码
<template>
<div class="box">
<div class="box-option">
<div :style="{ borderBottom: '1px solid #E9E9E9' }">
<a-checkbox
:indeterminate="indeterminate"
:checked="checkAll"
@change="onCheckAllChange"
>
Check all
</a-checkbox>
</div>
<br />
<div v-for="(item, index) in plainOptions" :key="item.val">
<a-checkbox
v-if="item.show"
:indeterminate="item.selectd"
:checked="item.tag"
@change="(e) => onChangePro(index, e)"
>
<a-popover placement="bottom">
<template slot="content">
<div v-for="(city, cityIndex) in item.city" :key="cityIndex">
<a-checkbox
v-if="city.show"
:checked="city.tag"
@change="(e) => onchangeCity(index, cityIndex, e)"
>
{{ city.val }}
</a-checkbox>
</div>
</template>
<template slot="title"></template>
{{ item.val }}
</a-popover>
</a-checkbox>
</div>
</div>
<div class="box-result">
<a-button type="primary" @click="onSubmitSelected">
提交
</a-button>
<div v-for="(item, index) in resultList" :key="index" class="row-data">
<h3 v-for="(val, idx) in item" :key="idx">{{ val }}</h3>
<a-button @click="onUpdateResult(item, index)">
修改
</a-button>
<a-button @click="onDeleteResult(item, index)">
删除
</a-button>
</div>
</div>
</div>
</template>
3.js部分
1.图片
2.代码
export default {
data() {
return {
indeterminate: false,
checkAll: false,
plainOptions: [],
resultList: [],
};
},
watch: {
//注意监听数组
plainOptions: {
handler(newVal, oldVal) {
// 别忘了show
// 但凡newVal中的tag有true的且是显示在页面上的,那么indeterminate就为true
// 如果所有的tag(其实也就是省级的tag)全为tag,那么indeterminate就为false,而checkAll为true
let falg = false;
newVal.forEach((v) => {
if (falg) {
return;
}
v.city.forEach((k) => {
if (k.tag && k.show) {
this.indeterminate = true;
this.checkAll = false;
falg = true;
return;
}
});
});
//全选
let res = newVal.every((v) => {
return v.tag == true;
});
this.checkAll = res;
if (res) {
this.indeterminate = false;
}
//全不选
if (!falg) {
this.indeterminate = false;
}
},
deep: true,
},
},
mounted() {
this.getData();
},
methods: {
getData() {
this.$axios.get("/data/casc-demo.json").then((res) => {
this.plainOptions = res.data;
});
},
onChangePro(index, e) {
this.plainOptions[index].tag = e.target.checked;
this.plainOptions[index].selectd = false;
this.handleProSelected(this.plainOptions[index]);
},
onchangeCity(index, cityIndex, e) {
this.plainOptions[index].city[cityIndex].tag = e.target.checked;
this.handleCitySelected(this.plainOptions[index], cityIndex);
},
onCheckAllChange(e) {
//所有的数据都根据e的值变化
this.plainOptions.forEach((v) => {
v.tag = e.target.checked;
v.selectd = false;
v.city.forEach((k) => {
k.tag = e.target.checked;
});
});
},
//省级选择,如果是选中会影响城市
handleProSelected(proData) {
proData.city.forEach((v) => {
v.tag = proData.tag;
});
},
//城市选择,查看省级是否需要选中
handleCitySelected(proData, cityIndex) {
let countTag = 0;
proData.city.forEach((v) => {
if (v.tag) {
countTag++;
}
});
if (countTag == 0) {
proData.tag = false;
proData.selectd = false;
} else if (countTag == proData.city.length) {
proData.tag = true;
proData.selectd = false;
} else {
proData.tag = false;
proData.selectd = true;
}
},
/*提交数据,将选中的数据的show设置为false,这样下次就不会显示了
需要得到的是市级,但是还有修改功能
如果省级的tag为true,那么省级以及市级的show都为false,
如果省级的selected为true,那么省级的show不变,而tag为true的市级的show为false
同时存储市级的val值,太变态了!!!只能一个一个的找到,因为后端返回的也是这个
*/
onSubmitSelected() {
let submitData = [];
this.plainOptions.forEach((v) => {
if (v.tag && v.show) {
v.show = false;
v.city.forEach((k) => {
k.show = false;
submitData.push(k.val);
});
} else if (v.selectd) {
v.selectd = false;
v.city.forEach((k) => {
if (k.tag && k.show) {
k.show = false;
submitData.push(k.val);
}
});
}
});
this.resultList.push(submitData);
},
//修改表格数据
onUpdateResult(val, idx) {
//将参数的值放回数组
this.handleChangeOptions(val, "update");
},
//删除该行
onDeleteResult(val, idx) {
this.resultList.splice(idx, 1);
this.handleChangeOptions(val, "delete");
},
/*搞成一个函数,方便删除和修改使用
根据参数,遍历数组,将show和tag修改
但凡有一个city被修改了,那么省级也要被修改
*/
handleChangeOptions(val, type) {
val.forEach((v) => {
this.plainOptions.forEach((k) => {
let flag = false;
k.city.forEach((z) => {
if (v == z.val) {
if (type == "delete") {
z.tag = false;
}
z.show = true;
flag = true;
}
});
if (flag) {
if (type == "delete") {
k.tag = false;
k.selectd = false;
} else if (k.tag) {
k.selectd = false;
} else {
k.selectd = true;
}
k.show = true;
}
});
});
},
},
};
3.css部分
.box {
margin: 20px;
}
.box-option {
padding-bottom: 100px;
}
.box-result {
padding-top: 20px;
}
.row-data {
display: flex;
padding: 10px 0;
border-bottom: 1px solid forestgreen;
}
h3 {
padding: 0 10px;
}