封装组件库-省市区选择器

2023, Feb 22    

实现省市区选择器

基于Element-plus框架的Select选择器,封装为省市区选择器。

初始配置

  • 注册路由组件chooseArea,配置为Container组件的子路由组件
  • 采用路由懒加载,箭头函数异步引入组件。
  • 注册通用组件ChooseArea,为路由组件的子组件,以便组件间通信。

省市区控制逻辑

  //利用Select选择器的disable属性进行控制,逻辑||表示前面为true返回前面,false返回后面
  <el-select placeholder="请选择省份" v-model="province">
      <el-option></el-option>
  </el-select>
  <el-select clearable :disabled="!province" placeholder="请选择城市" v-model="city" style="margin: 0 10px">
      <el-option></el-option>
  </el-select>
  <el-select clearable :disabled="!province || !city" placeholder="请选择区域" v-model="area">
      <el-option></el-option>
  </el-select>
  //省份
  let province = ref<string>('')
  //城市
  let city = ref<string>('')
  //地区
  let area = ref<string>('')

省市区数据获取并展示

在github上搜索省市区数据,格式为json

  import allAreas from '../lib/pca-code.json'
  let areas = ref(allAreas)
  //areas示例,code类型为string
  areas:{
          code:11,
          name:'北京',
          children:[]
        }
  • 省份数据获取
    <el-select clearable placeholder="请选择省份" v-model="province">
            <el-option v-for="item in areas" :key="item.code" :value="item.code" :label="item.name"></el-option>
    </el-select>
    
  • 所在省份的城市数据获取 定义接口类型,?定义在变量后面表示可选操作
    export interface AreaItem {
      name: string,
      code: string,
      children?: AreaItem[]
    }
    

    获取数据:

    let selectCity = ref<AreaItem[]>([])
    watch(()=>province.value,val=>{
        if(val){
            //!表示可将空值赋给变量并通过编译
            let cities = areas.value.find(item=>item.code === province.value)?.children!
            selectCity.value = cities
        }
        //监听province.value变化,则清空市和区
        city.value=''
        area.value = ''
    })
    <el-select clearable :disabled="!province" placeholder="请选择城市" v-model="city" style="margin: 0 10px">
      <el-option v-for="item in selectCity" :key="item.code" :value="item.code" :label="item.name"></el-option>
    </el-select>
    
  • 所在城市的区域数据获取
    let selectArea = ref<AreaItem[]>([])
    watch(()=>city.value,val=>{
        if(val){
            let area = selectCity.value.find((item:{code:string}) =>item.code===city.value)?.children!
            selectArea.value = area
        }
        area.value = ''
    })
    <el-select clearable :disabled="!province || !city" placeholder="请选择区域" v-model="area">
      <el-option v-for="item in selectArea" :key="item.code" :value="item.code" :label="item.name"></el-option>
    </el-select>
    

    向父组件传值

  • 传值类型
    export interface Data {
        name:string,
        code: string
    }
    
  • 与父组件通信
  //分发事件给父组件
  let emit = defineEmits(['change'])

  //监听区域
  watch(()=>area.value,val=>{
      //if条件的作用是,防止未选择区域时向父组件传值
      if(val){
          let provinceData: Data = {
          code: province.value,
          //&&的作用是确保province.value有值
          name: province.value && allAreas.find(item=>item.code === province.value)!.name,
      }
      let cityData: Data = {
          code: city.value,
          //必须要有city.value
          name: city.value && selectCity.value.find(item=>item.code===city.value)!.name
      }
      let areaData: Data = {
          code: area.value,
          name: area.value && selectArea.value.find(item=>item.code === area.value)!.name
      }
      emit('change',{
          province: provinceData,
          city: cityData,
          area: areaData
      })
      }    
  })
  • 父组件
  <my-choose-area @change="changeArea"></my-choose-area>
  let changeArea = (val: any)=>{
      console.log(val)
  }