需求是选了省份就显示省份,下面的耳机城市没有选择那么省份也不显示就显示已选城市,跟头条的投放一样的逻辑
<template>
<div class="cascader-input" v-if="input">
<el-input
placeholder="请输入内容"
v-model="searchInfo"
class="input-with-select search-input"
>
<template #append>
<el-button type="primary" @click="handleClickSearch">搜索</el-button>
</template>
</el-input>
</div>
<div class="cascader-box flex city-box">
<div class="select-cascader city">
<div class="cascader-title" style="padding-left: 10px;">
<el-switch v-model="allParent" active-color="#4371FF" inactive-color="#F5F6FA" @change="handleClickAllparent"></el-switch> {{parentList[0].parentType}}
</div>
<div class="select-cascader-box">
<div v-for="(item,i) in parentList" :key="i" class="flex city-icon">
<div><el-switch v-model="item.checked" active-color="#4371FF" inactive-color="#F5F6FA" @change="handleChangeParent($event, item.id)"></el-switch> {{item.name}}</div>
<span class="el-icon-arrow-right city-icon" v-if="item.children.length" @click="handleClickIcon(i)"></span>
</div>
</div>
</div>
<div class="select-cascader city" v-if="index > -1 && parentList[index].children.length">
<div class="cascader-title" style="padding-left: 10px;">
<el-switch v-model="allChild" active-color="#4371FF" inactive-color="#F5F6FA" @change="handleClickAllChild"></el-switch> {{parentList[index].children[0].childType}}
</div>
<div class="select-cascader-box">
<div v-for="(item,i) in parentList[index].children" :key="i">
<el-switch v-model="item.checked" active-color="#4371FF" inactive-color="#F5F6FA" @change="handleClickChild($event, parentList[index])"></el-switch> {{item.name}}
</div>
</div>
</div>
<div class="selectd-cascader">
<div class="cascader-title cascader-title-flex"><span>已选</span><span style="color:#4371FF;cursor: pointer;" @click="deleteAll">清空全部</span></div>
<div class="selectd-cascader-box">
<div v-for="(item,i) in selectList" :key="i" class="selectd-cascader-item">
<div>{{item.name}}</div>
<div class="selectd-close" @click="deleteItem(item.id)">X</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { defineComponent, onBeforeMount, reactive, ref, computed } from 'vue'
export default defineComponent({
setup(props) {
let list = reactive(props.list)
let selectList = reactive([])
let searchInfo = ref('')
let index = ref(-1)
let allParent = computed(() => parentList.findIndex(item => item.checked === false) === -1)
let allChild = computed(() => parentList[index.value].children.findIndex(item => item.checked === false) === -1)
let parentList = reactive([])
// 这里是根据传过来的list做了一个初始化,结构不同的话就改这里
function init () {
list.forEach(item => {
if (item.parentid == 1) {
parentList.push({
...item,
children: []
})
} else {
parentList.forEach(child => {
if (child.id === item.parentid) {
child.children.push(item)
}
})
}
})
parentList.splice()
}
// 全选省份
function handleClickAllparent (val) {
if (!val) {
index.value = -1
}
changeEleChecked(parentList, val)
setSelectList()
}
function handleClickAllChild (val) {
parentList[index.value].children.forEach(item => item.checked = val)
parentList[index.value].checked = val
setSelectList()
}
function handleChangeParent (val, id) {
// 判断是否是选中状态
let i; // 定义当前选中的省份索引
parentList.forEach((item,index) => {
if (item.id == id) {
i = index
// 改变该省份下所有城市的选中状态
item.children.forEach(child => {
child.checked = val
})
}
})
console.log('1',i);
index.value = i
setSelectList()
}
function handleClickSearch () {
parentList.forEach((item,i) => {
if (item.name === searchInfo.value) {
item.checked = true
item.children.forEach(child => {
child.checked = true
})
} else {
item.children.forEach(child => {
if (child.name === searchInfo.value) {
child.checked = true
index.value = i
}
})
}
})
setSelectList()
}
function handleClickChild (val, parent) {
// 点击选择省份时是选中状态,判断选中后的城市和总城市是否相同
let arr = parent.children.filter(child => child.checked)
if (arr.length == parent.children.length) {
// 相同要把全选城市和省份的选中状态改变
parent.checked = true
} else {
parent.checked = false
}
setSelectList()
}
function handleClickIcon (i) {
index.value = i
}
function deleteItem (id) {
for (let i = 0;i < parentList.length;i++) {
let item = parentList[i]
if (item.id === id) {
item.checked = false
item.children.forEach(child => {
child.checked = false
})
index.value = i
} else {
item.children.forEach(child => {
if (child.id === id) {
child.checked = false
item.checked = false
index.value = i
}
})
}
}
setSelectList()
}
function deleteAll () {
changeEleChecked(parentList, false)
setSelectList()
}
// 数组元素全部需要改变时
function changeEleChecked (list, parentStatus, childStatus) {
let arg = arguments.length
list.forEach(item => {
item.checked = parentStatus
if (item.children) {
item.children.forEach(child => {
child.checked = arg > 2 ? childStatus : parentStatus
})
}
})
}
// 列表选中了逻辑
function setSelectList () {
parentList.forEach(item => {
// 父元素被选中,已选列表添加父元素,子元素删除
if (item.checked) {
// 判断是否存在,如果不存在就push
if (isHaveEle(item, 'id') == -1) {
selectList.push(item)
}
// 父元素被选中删掉子元素
item.children.length ? item.children.forEach(child => {
if (isHaveEle(child, 'id') > -1) {
selectList.splice(isHaveEle(child, 'id'), 1)
}
}) : ''
} else if (!item.checked) {
// 如果没有被选中父元素,删掉父元素
if (isHaveEle(item, 'id') > -1) {
selectList.splice(isHaveEle(item, 'id'), 1)
}
item.children.length ? item.children.forEach(child => {
// 如果子元素被选中,判断列表中是否存在,不存在就push
if (child.checked) {
if (isHaveEle(child, 'id') == -1) {
selectList.push(child)
}
} else {
// 子元素没有被选中,判断是否列表中存在,存在就删掉
if (isHaveEle(child, 'id') > -1) {
selectList.splice(isHaveEle(child, 'id'), 1)
}
}
}) : ''
}
})
}
// 判断数组中是否已经存在某元素
function isHaveEle (ele, attr = 'id') {
return selectList.findIndex(item => item[attr] === ele[attr])
}
onBeforeMount(() => {
init()
})
return {
index,
searchInfo,
list,
selectList,
parentList,
allChild,
allParent,
handleClickAllparent,
handleClickAllChild,
handleChangeParent,
init,
handleClickSearch,
handleClickChild,
handleClickIcon,
deleteItem,
deleteAll,
setSelectList,
changeEleChecked
}
},
props: {
list: Object,
input: {
type: Boolean,
default: true
}
}
})
</script>
<style scoped lang="scss">
.cascader-input ::v-deep{
margin-left: 96px;
margin-top: 20px;
.el-input__inner {
width: 288px;
}
.el-input {
width: 288px;
}
.el-input-group__append, .el-input-group__prepend {
width: 76px;
height: 28px;
background: #4371FF;
border-radius: 0px 2px 2px 0px;
color: #fff;
border: none;
}
.el-button {
width: 76px;
}
}
.cascader-box {
margin-top: 12px;
margin-left: 96px;
.cascader-title {
background-color: #F5F6FA;
height: 26px;
line-height: 26px;
border-bottom: 1px solid #D3D5E0;
}
.select-cascader{
width: 352px;
height: 240px;
border-radius: 3px;
border: 1px solid #D3D5E0;
}
.city {
width: 183px;
&:nth-child(2) {
border-left: 0;
}
}
.selectd-cascader {
height: 240px;
width: 176px;
background: #F5F6FA;
padding: 0 10px;
border-radius: 3px;
overflow: hidden;
padding-bottom: 8px;
margin-left: 12px;
}
.cascader-title-flex {
display: flex;
justify-content: space-between;
margin-bottom: 8px;
font-size: 12px;
}
.select-cascader-box {
padding: 0 10px;
height: 213px;
overflow: auto;
}
.selectd-cascader-box {
height: 213px;
overflow: auto;
}
.selectd-cascader-item {
width: 156px;
height: 24px;
background: #DCE5FF;
border-radius: 3px;
color: #4371FF;
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 8px;
margin-bottom: 8px;
}
.selectd-close {
cursor: pointer;
}
.city-icon {
justify-content: space-between;
}
}
.city-box {
margin-top: 8px;
}
</style>
// 这是父组件传的list
list: [{
name: '北京',
id: 1,
checked: false,
parentid: 1,
parentType: '省份'
},{
name: '山西',
id: 2,
checked: false,
parentid: 1,
parentType: '省份'
},{
name: '太原',
parentid: 2,
id: 3,
checked: false,
childType: '城市'
},{
name: '大兴',
id: 4,
parentid: 2,
checked: false,
childType: '城市'
},{
name: '内蒙',
id: 5,
checked: false,
parentid: 1,
parentType: '省份'
},{
name: '呼市',
parentid: 5,
id: 6,
checked: false,
childType: '城市'
},{
name: '赤峰',
id: 7,
parentid: 5,
checked: false,
childType: '城市'
}],
一开始写的比较乱后来改良了一下,所以可能也有冗余的地方,可以指出来共同进步