vue3如何使用vant-picker封装省市二级联动

 更新时间:2022年10月13日 14:55:20   作者:脑子不太灵光的程序员  
这篇文章主要介绍了vue3如何使用vant-picker封装省市二级联动,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

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

近期用上了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="@/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: '请选择地区',
    },
  },
  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="地区" 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;
}

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

相关文章

  • Vue3 源码分析reactive readonly实例

    Vue3 源码分析reactive readonly实例

    这篇文章主要为大家介绍了Vue3 源码分析reactive readonly实例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-10-10
  • vue使用i18n实现国际化的方法详解

    vue使用i18n实现国际化的方法详解

    这篇文章主要给大家介绍了关于vue使用i18n如何实现国际化的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用vue具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-09-09
  • 详解Vue SPA项目优化小记

    详解Vue SPA项目优化小记

    这篇文章主要介绍了详解Vue SPA项目优化小记,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-07-07
  • 详解vue中父子组件传递参数props的实现方式

    详解vue中父子组件传递参数props的实现方式

    这篇文章主要给大家介绍了在vue中,父子组件传递参数 props 实现方式,文章通过代码示例介绍的非常详细,对我们的学习或工作有一定的参考价值,需要的朋友可以参考下
    2023-07-07
  • Vue基础语法知识梳理下篇

    Vue基础语法知识梳理下篇

    这篇文章主要介绍了Vue基础语法知识梳理,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-12-12
  • 基于Vue2实现数字纵向滚动效果

    基于Vue2实现数字纵向滚动效果

    这篇文章主要为大家详细介绍了如何基于Vue2实现数字纵向滚动效果,从而达到显示计时器滚动效果,感兴趣的小伙伴可以跟随小编一起学习一下
    2024-03-03
  • vue动态添加store、路由和国际化配置方式

    vue动态添加store、路由和国际化配置方式

    这篇文章主要介绍了vue动态添加store、路由和国际化配置方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-03-03
  • Vue 2.0中生命周期与钩子函数的一些理解

    Vue 2.0中生命周期与钩子函数的一些理解

    这篇文章主要给大家介绍了关于Vue 2.0中生命周期与钩子函数的相关资料,对大家学习或者使用vue2.0具有一定的参考学习价值,需要的朋友们下面随小编一起来看看吧。
    2017-05-05
  • Vue中路由的使用方法实例详解

    Vue中路由的使用方法实例详解

    本文为大家介绍Vue中路由的使用方法,包括安装路由创建路由并导出以及在应用实例中使用vue-router的相关知识,本文结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2024-02-02
  • Vue-loader使用教程

    Vue-loader使用教程

    Vue-loader其实就是一个webpack的loader,用来把vue组件转换成可部署的js, html, css模块,这篇文章主要介绍了Vue-loader使用教程,需要的朋友可以参考下
    2022-08-08

最新评论