vue3如何使用vant-picker封裝省市二級聯(lián)動
怕什么真理無窮,進一步有進一步的歡喜呀,不得不承認的就是,興趣和擅長是一個良性迭代的循環(huán)啊,你擅長某件事情,就會越喜歡它,越喜歡,就越愿意花時間,進而越擅長。所以代碼碼起來吧哈哈哈
近期用上了vue3,還順手寫了個小需求,用vant-picker封裝一個省市的二級聯(lián)動,并且在從后端接口獲取省市的數(shù)據(jù),點開彈出框需要展示默認的選項,比如點擊廣東省-深圳市輸入框,彈出的picker級聯(lián)選擇器需要默認廣東 -深圳。
如下圖:

好,那么話不多說,接下來一步一步來實現(xiàn)。
首先,項目中引入vant-ui
import { Popup, Picker } from 'vant'
components: {
[Picker.name]: Picker,
[Popup.name]: Popup,
},vant官網(wǎng)中,地區(qū)聯(lián)動的形式是這樣的

而我的數(shù)據(jù)格式是這樣的
[ {
"citys": [
{
"cityName": "北京市"
}
],
"provinceName": "北京市"
},
{
"citys": [
{
"cityName": "天津市"
}
],
"provinceName": "天津市"
},
{
"citys": [
{
"cityName": "上海市"
}
],
"provinceName": "上海市"
},
{
"citys": [
{
"cityName": "重慶市"
}
],
"provinceName": "重慶市"
},]
然后對數(shù)據(jù)做了處理,處理成官網(wǎng)的形式,這樣就可以聯(lián)動了
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父子組件的傳值就不過多贅述了,有需要可自行查看官方文檔
接下來說一說,點開彈出框需要展示默認的選項怎么實現(xiàn)的吧,此處,vant官網(wǎng)給出了一個api,不過沒有使用示例,搗鼓了半天。

使用setIndexes設置獲取到的索引值,就可以實現(xiàn)點開彈出框需要展示默認的選項了,在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="@/assets/icons/lineCross.svg" />
</div>
</template>
<template v-slot:title>
<p class="title">{{ title }}</p>
</template>
<template v-slot:confirm>
<div class="icon--button">
<img src="@/assets/icons/lineHook.svg" />
</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: '請選擇地區(qū)',
},
},
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="./index.scss" />
父組件代碼
<template>
<div>
<van-field v-model="areaValue" label="地區(qū)" placeholder="請輸入地區(qū)" @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;
}以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
vue3中使用@vueuse/core中的圖片懶加載案例詳解
這篇文章主要介紹了vue3中使用@vueuse/core中的圖片懶加載案例,本文通過實例代碼給大家介紹的非常詳細,需要的朋友可以參考下2023-03-03

