首页IT科技vue实现二级联动(vue3如何使用vant-picker封装省市二级联动)

vue实现二级联动(vue3如何使用vant-picker封装省市二级联动)

时间2025-09-19 10:39:00分类IT科技浏览7053
导读:怕什么真理无穷,进一步有进一步的欢喜呀,不得不承认的就是,兴趣和擅长是一个良性迭代的循环啊,你擅长某件事情,就会越喜欢它,越喜欢,就越愿意花时间,进而越擅长。所以代码码起来吧哈哈哈...

怕什么真理无穷                    ,进一步有进一步的欢喜呀                          ,不得不承认的就是        ,兴趣和擅长是一个良性迭代的循环啊               ,你擅长某件事情                           ,就会越喜欢它            ,越喜欢          ,就越愿意花时间                            ,进而越擅长                。所以代码码起来吧哈哈哈

近期用上了vue3                ,还顺手写了个小需求     ,用vant-picker封装一个省市的二级联动                             ,并且在从后端接口获取省市的数据                    ,点开弹出框需要展示默认的选项,比如点击广东省-深圳市输入框                         ,弹出的picker级联选择器需要默认广东 -深圳                            。

如下图:

好                         ,那么话不多说    ,接下来一步一步来实现          。

首先                    ,项目中引入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去设置相应的索引即可                           。

onMounted(() => { const cityName = toRef(props, areaValue).value.split(-) const findProvinceName = columnsData.findIndex((value) => value.text === cityName[0]) const findCityName = columnsData[findProvinceName].children.findIndex((value) => value.text === cityName[1]) areaPicker.value?.setIndexes([findProvinceName, findCityName]) })

你以为这样就结束了吗,no no no,还要在popup 中设置lazy-render为false                         ,这样就结束拉~

好吧废话不多说                         ,上子组件代码

子组件代码PickerArea

<template> <div class="container"> <van-popup v-model:show="refShowOverlay" position="bottom" :lazy-render="false" round> <van-picker ref="areaPicker" show-toolbar :columns="columnsData" value-key="text" @change="handleChangeArea" @cancel="handleCancelArea" @confirm="handleConfirmArea" > <template v-slot:cancel> <div class="icon--button"> <img src="" /> </div> </template> <template v-slot:title> <p class="title">{{ title }}</p> </template> <template v-slot:confirm> <div class="icon--button"> <img src="" /> </div> </template> </van-picker> </van-popup> </div> </template> <script lang="ts"> import { defineComponent, ref, toRef, watch, reactive, 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: { areaValue: { type: String, default: , }, show: { type: Boolean, default: false, }, showDatePicker: { type: Boolean, default: false, }, title: { type: String, default: 请选择地区, }, }, setup(props, { emit }) { const refShowOverlay = 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 } }) const handleChangeArea = (area: Array<{ text: string }>) => { emit(change-area, area) } const handleConfirmArea = (area: Array<{ text: string }>) => { emit(confirm-area, area) handleCancelArea() } watch(computedShowOverlay, (nV) => { refShowOverlay.value = nV }) onMounted(() => { const cityName = toRef(props, areaValue).value.split(-) const findProvinceName = columnsData.findIndex((value) => value.text === cityName[0]) const findCityName = columnsData[findProvinceName].children.findIndex((value) => value.text === cityName[1]) areaPicker.value?.setIndexes([findProvinceName, findCityName]) }) return { refShowOverlay, areaPicker, columnsData, handleChangeArea, handleCancelArea, handleConfirmArea, } }, }) </script> <style lang="scss" scoped src="https://www.jb51.net/article/index.scss" />

父组件代码

<template> <div> <van-field v-model="areaValue" label="地区" placeholder="请输入地区" @click="handleClickOFF" /> <tas-picker-china-area :show-date-picker="show" @close="show = false" @confirm-area="handleConfirmArea" @change-area="handleChangeArea" :areaValue="areaValue" /> </div> </template> <script lang="ts"> import { computed, defineComponent, ref, watch, reactive, toRefs } from vue import { Field } from vant import { px2remWithUnit } from @/utils/ui import { getThemeVarValue } from @/config/ui import { showDialog } from ./components/TasDialog/dialog import TasPickerChinaArea from @/components/TasPickerChinaArea/index.vue export default defineComponent({ name: TasButton, components: { [Field.name]: Field, TasPickerChinaArea, }, setup() { const show = ref(false) const refShowDatePicker = ref(true) const areaValue = ref(广东省-深圳市) const handleClickOFF = () => { show.value = !show.value } const handleConfirmArea = (area: Array<{ text: string }>) => { areaValue.value = `${area[0].text} - ${area[1].text}` } const handleChangeArea = (area: Array<{ text: string }>) => {} return { show, areaValue, refShowDatePicker, handleClickOFF, handleConfirmArea, handleChangeArea, } }, }) </script>

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; }

以上为个人经验    ,希望能给大家一个参考                    ,也希望大家多多支持本站               。

声明:本站所有文章                          ,如无特殊说明或标注        ,均为本站原创发布        。任何个人或组织               ,在未征得本站同意时                           ,禁止复制                    、盗用                          、采集        、发布本站内容到任何网站               、书籍等各类媒体平台                          。如若本站内容侵犯了原著者的合法权益            ,可联系我们进行处理                    。

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
mac osx10.11(苹果Mac OS X 10.10 Yosemite系统十大使用技巧汇总)