ThreeLevelRegionSelector.vue 3.95 KB
<template>
  <div class="three-level-region-selector">
    <el-row :gutter="10">
      <el-col :span="8">
        <el-select 
          v-model="selectedProvince" 
          placeholder="选择省份"
          clearable
          @change="handleProvinceChange"
          style="width: 100%;"
        >
          <el-option
            v-for="province in provinces"
            :key="province"
            :label="province"
            :value="province"
          ></el-option>
        </el-select>
      </el-col>
      <el-col :span="8">
        <el-select 
          v-model="selectedCity" 
          placeholder="选择地市"
          clearable
          @change="handleCityChange"
          :disabled="!selectedProvince"
          style="width: 100%;"
        >
          <el-option
            v-for="city in cities"
            :key="city"
            :label="city"
            :value="city"
          ></el-option>
        </el-select>
      </el-col>
      <el-col :span="8">
        <el-select 
          v-model="selectedDistrict" 
          placeholder="选择区县"
          clearable
          :disabled="!selectedCity"
          style="width: 100%;"
        >
          <el-option
            v-for="district in districts"
            :key="district"
            :label="district"
            :value="district"
          ></el-option>
        </el-select>
      </el-col>
    </el-row>
  </div>
</template>

<script>
// 地区数据
const regionData = {
  '江苏省': {
    '南京市': ['玄武区', '秦淮区', '建邺区', '鼓楼区', '浦口区', '栖霞区', '雨花台区', '江宁区', '六合区', '溧水区', '高淳区'],
    '南通市': ['崇川区', '港闸区'],
    '苏州市': ['姑苏区', '虎丘区']
  }
}

export default {
  name: 'ThreeLevelRegionSelector',
  props: {
    value: {
      type: Object,
      default: () => ({
        province: '',
        city: '',
        district: ''
      })
    },
    placeholder: {
      type: String,
      default: '请选择区域'
    }
  },
  data() {
    return {
      selectedProvince: this.value.province,
      selectedCity: this.value.city,
      selectedDistrict: this.value.district
    }
  },
  computed: {
    provinces() {
      return Object.keys(regionData)
    },
    cities() {
      if (!this.selectedProvince) return []
      return Object.keys(regionData[this.selectedProvince])
    },
    districts() {
      if (!this.selectedProvince || !this.selectedCity) return []
      return regionData[this.selectedProvince][this.selectedCity]
    }
  },
  watch: {
    value: {
      handler(newVal) {
        this.selectedProvince = newVal.province || ''
        this.selectedCity = newVal.city || ''
        this.selectedDistrict = newVal.district || ''
      },
      deep: true
    },
    selectedProvince() {
      if (!this.provinces.includes(this.selectedProvince)) {
        this.selectedCity = ''
        this.selectedDistrict = ''
      }
      this.emitChange()
    },
    selectedCity() {
      if (!this.cities.includes(this.selectedCity)) {
        this.selectedDistrict = ''
      }
      this.emitChange()
    },
    selectedDistrict() {
      this.emitChange()
    }
  },
  methods: {
    handleProvinceChange() {
      if (!this.provinces.includes(this.selectedProvince)) {
        this.selectedCity = ''
        this.selectedDistrict = ''
      }
      this.emitChange()
    },
    handleCityChange() {
      if (!this.cities.includes(this.selectedCity)) {
        this.selectedDistrict = ''
      }
      this.emitChange()
    },
    emitChange() {
      this.$emit('input', {
        province: this.selectedProvince,
        city: this.selectedCity,
        district: this.selectedDistrict
      })
      this.$emit('change', {
        province: this.selectedProvince,
        city: this.selectedCity,
        district: this.selectedDistrict
      })
    }
  }
}
</script>

<style lang="scss" scoped>
.three-level-region-selector {
  .el-select {
    ::v-deep .el-input__inner {
      border-radius: 4px;
    }
  }
}
</style>