怕什么真理无穷 ,进一步有进一步的欢喜呀 ,不得不承认的就是 ,兴趣和擅长是一个良性迭代的循环啊 ,你擅长某件事情 ,就会越喜欢它 ,越喜欢 ,就越愿意花时间 ,进而越擅长 。所以代码码起来吧哈哈哈
近期用上了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;
}
以上为个人经验,希望能给大家一个参考 ,也希望大家多多支持本站 。
声明:本站所有文章 ,如无特殊说明或标注 ,均为本站原创发布 。任何个人或组织 ,在未征得本站同意时 ,禁止复制 、盗用 、采集 、发布本站内容到任何网站 、书籍等各类媒体平台 。如若本站内容侵犯了原著者的合法权益 ,可联系我们进行处理 。