- 最近在做一个移动端的H5项目,从后端获取省市区数据实现省市区等数据多级联动,运用的vant,大家可以先去有赞官网看Cascader的介绍,链接:有赞Vant3.6.12(没错我用的是3);
<template>
<van-field v-model="userInfo.nowAddress" placeholder="请输入现居住地址" label="现居住地址" input-align="right" @click="onClickCascader" />
<!--现居住地址 级联选择框 -->
<van-popup v-model:show="showCascader" round position="bottom">
<van-cascader v-model="cascaderAddress" title="请选择所在地区" :options="options" @close="showCascader = false"
@change="onChange" @finish="onFinish" />
</van-popup>
</template>
- 由于我的项目的地址是固定广东省,所以options初始值设置为:
options: [{
text: '广东省',
value: '440000',
children: [],
}],
- 后端根据value的传值获取不同的市、区、街道等,直到返回为空;
<script>
import { Cascader, Popup } from 'vant'
import { reactive, toRefs } from "vue"
import { getAllCity } from "@api/user"
export default {
name: 'userInfo',
components: {
[Cascader.name]: Cascader,
[Popup.name]: Popup,
},
setup() {
const state = reactive({
userInfo: {//用户个人信息,此处只放现居住地址nowAddress
nowAddress:'',
},
showCascader: false,//是否显示级联选择
cascaderAddress: '',//绑定的是当前选择的 value值(如:选择了广东省,当前值为440000)
options: [{
text: '广东省',
value: '440000',
children: [],
}],
});
const onClickCascader = () => {
state.showCascader = true;
};
//获取数据
const getAreas = async (value) => {
const { result } = await getAllCity(value);
return result;
};
const onChange = ({ value, tabIndex, selectedOptions }) => {
if (tabIndex === 0) {
getAreas(value).then((res) => {
if (res.length) {
addTree(selectedOptions, res, value);
}
});
}
};
const addTree = (selectedOptions, res, value) => {
selectedOptions.forEach(item => {
if (item.value === value) {
item.children = res;
}
})
};
const onFinish = ({ value, tabIndex, selectedOptions }) => {
console.log('onFinish', selectedOptions, state.finishIndex, tabIndex);
state.showCascader = false;
state.userInfo.nowAddress = selectedOptions.map((option) => option.text).join('');
};
return {
...toRefs(state),
onClickCascader,
onChange,
onFinish
}
}
}
</script>
-
此处需要着重说明的是,点击广东省的时候(tabIndex=0),触发的是onChange 事件,但是后续选择会触发onChange 事件和onFinish事件,本身我以为下图事件说明的意思是点击不同的省、市、区、街道…触发的是onChange 事件,直到选择完最后一层(该层没有了children属性)就表明全部选项选择完成,触发onFinished事件;
-
上述代码就是onChange 事件为每个层级获取children数数组,onFinish事件则关闭级联选择(state.showCascader = false;),并将选择的所有数据进行拼接获取nowAddress 的值(state.userInfo.nowAddress = selectedOptions.map((option) => option.text).join(‘’););
-
但是事实结果不是这样,除了第一层点击没有问题之外,点击第二层以及往后的每一层,级联选择器会关闭了,再次点击打开,数据还保存在上一次点击的状态,很明显,这触发了onFinish事件,关闭了级联选择器。
-
我尝试在onFinish事件中进行判断,记录当请求数据为空的时候,说明当前层级没有children,试了之后发现并不能控制onFinish事件的触发,该事件并不根据是说没有children属性就触发onFinish事件;
-
试了很多次,不知道是我理解问题还是我哪里出错了;
-
如图:
- 选择第一层:只触发onChange 事件
-
选择第二层:触发onChange 事件和onFinish事件
-
选择第三层:触发onChange 事件和onFinish事件
-
后续层级不再赘述
-
如果我的理解错了的话,根据上述得出结果:首次点击触发onChange ,后面触发onFinished,因此,为了控制
- 解决办法:
首次点击 在onChange事件中插入数据,后续点击,在onFinish 中插入数据,存在则插入,不存在则关闭级联选择器,问题解决;
const onChange = ({ value, tabIndex, selectedOptions }) => {
console.log('onChange',value, tabIndex, selectedOptions[tabIndex].text);
if (tabIndex === 0) {
getAreas(value).then((res) => {
if (res.length) {
addTree(selectedOptions, res, value);
}
});
}
};
const onFinish = ({ value, tabIndex, selectedOptions }) => {
console.log('onFinish', value, tabIndex, selectedOptions[tabIndex].text);
getAreas(value).then((res) => {
if (res.length) {
addTree(selectedOptions, res, value);
} else {
state.showCascader = false;
state.userInfo.nowAddress = selectedOptions.map((option) => option.text).join('');
}
});
};
- 看了下很多文档并没有类似问题以及说明,记录一下,希望给你一点思路;
- 当然该解决办法不一定是最优的,欢迎来讨论。