【Vue3】vue3 + ts 封装城市选择组件
迪丽瓦拉
2024-05-27 08:08:46
0

城市选择-基本功能

能够封装城市选择组件,并且完成基础的显示隐藏的交互功能

(1)封装通用组件src/components/city/index.vue



全局注册

import XtxCity from '@/components/city/index.vue'
export default {install(app: App) {app.component('City', City)},
}

提供类型 src/global.d.ts

import XtxCity from '@/components/city/index.vue'
declare module 'vue' {City: typeof City}
}

(2)在商品详情组件中渲染city组件 src/views/goods/components/goods-name.vue

配送

(3)控制城市的显示和隐藏

  1. 点击的时候切换省市区的样式
  2. 切换城市弹层的显示或隐藏

(4)点击弹层外部,关闭弹层



城市选择-动态渲染

需求:完成城市数据的获取以及渲染

注意

城市数据并不是直接从接口服务器中获取的,而是从阿里云服务器上获取的数据,所以不能使用封装好的request发送请求,直接使用 原生的axios 发送请求即可。https://yjy-oss-files.oss-cn-zhangjiakou.aliyuncs.com/tuxian/area.jsonopen in new window

(1)定义数据类型

// 城市列表类型
export type AreaList = {code: stringlevel: numbername: stringareaList: AreaList[]
}

(2)获取数据src/components/city/index.vue

需求: 从接口获取城市数据,赋值给本地数据

  1. 定义列表数据变量 const cityList = ref([])
  2. 封装调接口的方法
  3. 方法内部调用接口,把获取到的结果赋值给cityList
  4. 调用方法

(3)渲染数据src/components/City/index.vue


(4)点击弹层外部,关闭弹层



城市选择-交互逻辑

在这里插入图片描述

需求:

  1. 点击选择省市区的时候能够把省市区数据存储起来
    1. 根据点击的每一个节点的level决定他应该存储到省/城/区的哪个下面
    2. 点击的时候,需要把当前弹层城市信息替换为当前点击节点的子节点的城市信息(点击省显示市,点击市显示县)
    3. 如果点击的是区的节点,则需要关弹层
    4. 如果中途点击了关闭弹层,则需要重置城市数据

点击某个省,显示省下面的市。点击市,显示市下面的县。

根据level判断级别。

(1)给城市注册点击事件

{{ item.name }}

(2)城市切换逻辑

// 选择城市
const changeResult = ref({provinceCode: '',provinceName: '',cityCode: '',cityName: '',countyCode: '',countyName: ''
})const selectCity = (city: AreaList) => {if (city.level === 0) {// 省changeResult.value.provinceName = city.namechangeResult.value.provinceCode = city.codecityList.value = city.areaList}if (city.level === 1) {// 市changeResult.value.cityName = city.namechangeResult.value.cityCode = city.codecityList.value = city.areaList}if (city.level === 2) {// 县(区)changeResult.value.countyName = city.namechangeResult.value.countyCode = city.code// 关闭弹窗active.value = false}
}

(3)关闭时恢复城市数据

const cityList = ref([])
const cacheList = ref([])const getCityData = async () => {const {data:res} = await axios.get('https://yjy-oss-files.oss-cn-zhangjiakou.aliyuncs.com/tuxian/area.json')cityList.value = rescacheList.value = res
}
getCityData()// 监听关闭弹窗的处理,恢复数据
watch(active, (value) => {// 当关闭active的时候,需要回复数据if (!value) {cityList.value = cacheList.value}
})

城市选择-完整地址处理

需求描述

  1. 默认展示的配送地址需要从父组件传递过来(登录的用户可以拿到当前用户的默认配送地址)
  2. 子组件选择完省市区需要传递给父组件,由父组件组织数据传给子组件进行展示(默认展示配送地址的数据源在父组件)

注意:完整地址需要父组件传递给子组件,将来如果登录的用户,父组件可以获取到完整的地址。

(1)父组件将城市数据传递给子组件


(2)子组件接收,并且进行展示

注意点:具体的地址和请选择配送同时只展示一个

defineProps<{userAddress?: string
}>()
{{ userAddress }}请选择配送地址

(3)子组件选择完城市,需要将数据传递给父组件

// 选择的城市结果类型
export type CityResult = {provinceCode: stringprovinceName: stringcityCode: stringcityName: stringcountyCode: stringcountyName: string
}const changeResult = ref>({})const emit = defineEmits<{(e: 'changeCity', value: CityResult): void
}>()const selectCity = (city: AreaList) => {if (city.level === 0) {// 省changeResult.value.provinceName = city.namechangeResult.value.provinceCode = city.codecityList.value = city.areaList}if (city.level === 1) {// 市changeResult.value.cityName = city.namechangeResult.value.cityCode = city.codecityList.value = city.areaList}if (city.level === 2) {// 县(区)changeResult.value.countyName = city.namechangeResult.value.countyCode = city.code// 关闭弹窗active.value = false// 子传父emit('changeCity', changeResult.value)}
}

优化代码(可选)

const changeResult = ref>({})
// record接受两个泛型参数,第一个为对象key的类型,第二个为对象值的类型
const cityMap: Record = {0: 'province',1: 'city',2: 'county'
}
const selectedCity = (city: AreaList) => {changeResult.value[`${cityMap[city["level"]]}Name`] = city.namechangeResult.value[`${cityMap[city["level"]]}Code`] = city.codeif (city.level === 2) {setIsShowCity(false)emits('changeCity', changeResult.value)} else {cityList.value = city.areaList}
}

(4)父组件接受数据并且处理

配送
const userAddress = ref('江西省 九江市 不知道县') const changeCity = (changeResult: CityResult) => {userAddress.value =changeResult.provinceName +' ' +changeResult.cityName +' ' +changeResult.countyName } ', changeResult.value)} else {cityList.value = city.areaList} }

(4)父组件接受数据并且处理

配送
const userAddress = ref('江西省 九江市 不知道县') const changeCity = (changeResult: CityResult) => {userAddress.value =changeResult.provinceName +' ' +changeResult.cityName +' ' +changeResult.countyName }

相关内容