vue3 使用vant-picker封装省市二级联动,设置默认值
怕什么真理无穷,进一步有进一步的欢喜呀,不得不承认的就是,兴趣和擅长是一个良性迭代的循环啊,你擅长某件事情,就会越喜欢它,越喜欢,就越愿意花时间,进而越擅长。所以代码码起来吧哈哈哈
近期用上了vue3,还顺手写了个小需求,用vant-picker封装一个省市的二级联动,并且在从后端接口获取省市的数据,点开弹出框需要展示默认的选项,比如点击广东省-深圳市输入框,弹出的picker级联选择器需要默认广东 -深圳。如下图: yy 好,那么话不多说,接下来一步一步来实现。 首先,项目中引入vant-ui
import { Popup, Picker } from 'vant'
components: {
[Picker.name]: Picker,
[Popup.name]: Popup,
},
vant官网中,地区联动的形式是这样的  而我的数据格式是这样的
[ {
"citys": [
{
"cityName": "北京市"
}
],
"provinceName": "北京市"
},
{
"citys": [
{
"cityName": "天津市"
}
],
"provinceName": "天津市"
},
{
"citys": [
{
"cityName": "上海市"
}
],
"provinceName": "上海市"
},
{
"citys": [
{
"cityName": "重庆市"
}
],
"provinceName": "重庆市"
},]
然后对数据做了处理,处理成官网的形式,这样就可以联动了
const columnsData = chinaAreaDataType.map((item, index) => {
const children: { text: string }[] = []
item.citys.forEach((item) => {
children.push({
text: item.cityName,
})
})
return { text: item.provinceName, children }
})
其中关于一些vue3父子组件的传值就不过多赘述了,有需要可自行查看官方文档 接下来说一说,点开弹出框需要展示默认的选项怎么实现的吧,此处,vant官网给出了一个api,不过没有使用示例,捣鼓了半天。  使用setIndexes设置获取到的索引值,就可以实现点开弹出框需要展示默认的选项了,在onMounted中通过ref去设置相应的索引即可。
你以为这样就结束了吗,no no no,还要在popup 中设置lazy-render为false,这样就结束拉~ 好吧废话不多说,上子组件代码 子组件代码PickerArea
<template>
<div class="container">
<van-popup v-model:show="showOverlay" position="bottom" round>
<van-picker
ref="areaPicker"
show-toolbar
:columns="columnsData"
value-key="text"
@change="handleChange"
@cancel="handleCancelArea"
@confirm="handleConfirmArea"
>
<template v-slot:cancel>
<div class="icon--button">
<img src="@/assets/icons/lineCross.svg" alt="" />
</div>
</template>
<template v-slot:title></template>
<template v-slot:confirm>
<div class="icon--button">
<img src="@/assets/icons/lineHook.svg" alt="" />
</div>
</template>
</van-picker>
</van-popup>
</div>
</template>
<script lang="ts">
import { defineComponent, ref, toRef, watch, reactive, computed, Ref, onMounted } from 'vue'
import { Popup, Picker, Field } from 'vant'
import chinaAreaDataType from './chinaAreaData.json'
export default defineComponent({
name: 'TasPickerArea',
components: {
[Picker.name]: Picker,
[Popup.name]: Popup,
[Field.name]: Field,
},
props: {
show: {
type: Boolean,
default: false,
},
showDatePicker: {
type: Boolean,
default: false,
},
},
setup(props, { emit }) {
const areaValue = ref('')
const showOverlay = ref(false)
const computedShowOverlay = toRef(props, 'showDatePicker')
const areaPicker = ref<typeof Picker>()
const handleCancelArea = () => {
emit('close', false)
}
const columnsData = chinaAreaDataType.map((item, index) => {
const children: { text: string }[] = []
item.citys.forEach((item) => {
children.push({
text: item.cityName,
})
})
return { text: item.provinceName, children }
})
let handleChange = (values: any, index: number, picker: any) => {
areaPicker.value?.setColumnIndex(1, columnsData[values[0]])
}
const handleConfirmArea = (area: Array<{ text: string }>) => {
emit('confirm-area', area)
areaValue.value = `${area[0].text} - ${area[1].text}`
handleCancelArea()
}
watch(computedShowOverlay, (nV) => {
showOverlay.value = nV
})
onMounted(() => {
columnsData.forEach((item, index) => {
item.children.forEach((item, index) => {
console.log(index, ':', item)
})
})
console.log(areaPicker.value?.setColumnIndex(1, columnsData[0]), '$refs')
})
return {
areaValue,
showOverlay,
areaPicker,
columnsData,
handleChange,
handleCancelArea,
handleConfirmArea,
}
},
})
</script>
<style lang="scss" scoped src="./index.scss" />
css代码
.container {
overflow: hidden;
&::v-deep(.van-picker-column) {
font-size: 32px;
}
::v-deep(.van-picker__toolbar) {
height: auto;
padding: 30px 45px;
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
}
}
.icon--button img {
width: 52px;
}
.title {
font-size: 32px;
font-weight: 500;
color: #000000;
line-height: 45px;
}
如有不妥之处,还请大佬指出~
|