vue地区选择器(到乡镇,到区,到市)

在现代 Web 开发中,用户体验至关重要,而表单的设计常常是提升体验的关键环节之一。随着 Vue.js 的广泛应用,许多开发者开始寻求简洁、高效的方式来处理复杂的选择输入,特别是在需要用户选择地区信息的场景下。

想象一下,当用户在一个表单中需要准确选择省、市、区、乡镇等层级的地址时,一个直观易用的地区选择器将会极大地提升用户的操作便捷性。通过使用 Vue 及其生态系统中的组件库,比如 Element Plus,我们可以轻松实现一个层级清晰、交互友好的地区选择器界面。

本文将带您深入了解如何在 Vue 应用中构建一个地区选择器,从最顶层的省份到最底层的乡镇。我们将涵盖组件的实现、数据管理和样式美化等多个维度,帮助您不仅能实现基本功能,还能提升用户体验,让用户在选择地区时流畅而开心。

无论你是 Vue 开发新手还是有一定经验的开发者,这篇文章都将为你提供实用的知识和技巧,帮助你打造更加出色的用户界面。接下来,让我们一起开始这个旅程吧!

第一步 下载  element-china-area-data

npm install element-china-area-data

这里选择element plus的级联选择器,所以没有安装element plus的

npm install element-plus
  • 第一个选择到乡镇的数据需要我们自己下载 因为博主也是找了好久有没有现成的数据 
下载地址

下载之后将导入到项目中,博主这里是导入到 assets文件夹里,大家也可以修改,但是不在assets里的话,在RegionView.vue导入时要修改导入路径

新建一个页面 RegionView.vue

<template>
  <div>
    <div class="cascader-container">
      <h2 class="title">到乡镇选择地区</h2>
      <el-cascader
          :options="options"
          :props="{ checkStrictly: true, value: 'code', label: 'name' }"
          ref="cascaderAddr"
          v-model="selectedOptions"
          @change="handleChange"
          clearable
          class="cascader"
      >
        <template #default="{ node, data }">
          <span>{{ data.name }}</span>
          <span v-if="!node.isLeaf"> ({{ data.children.length }}) </span>
        </template>
      </el-cascader>
      <div class="address-info">
        <div class="info-item">地区编码:<strong>{{ addrCodes.join(',') }}</strong></div>
        <div class="info-item">地区:<strong>{{ addrCodesSelected.join('') }}</strong></div>
      </div>
    </div>
    <div class="cascader-container">
      <h2 class="title">到区选择地区</h2>
      <el-cascader
          size="large"
          :options="regionData"
          @change="handleChange1"
          class="cascader"
          v-model="selectedOptions1">
      </el-cascader>
      <div class="address-info">
        <div class="info-item">地区编码:<strong>{{ temp.areaCode.join(',') }}</strong></div>
        <div class="info-item">地区:<strong>{{ temp.areaName.join('') }}</strong></div>
      </div>
    </div>
    <div class="cascader-container">
      <h2 class="title">到市选择地区</h2>
      <el-cascader
          size="large"
          :options="provinceAndCityData"
          @change="handleChange2"
          class="cascader"
          v-model="selectedOptions2">
      </el-cascader>
      <div class="address-info">
        <div class="info-item">地区编码:<strong>{{ areaCode.join(',') }}</strong></div>
        <div class="info-item">地区:<strong>{{ areaName.join('') }}</strong></div>
      </div>
    </div>
  </div>

</template>

<script>
let pcas = require('@/assets/pcas-code.json');
import {regionData,provinceAndCityData ,codeToText} from 'element-china-area-data';
export default {
  name: 'RegionView',
  data() {
    return {
      options: pcas,
      provinceAndCityData,
      selectedOptions: [],
      addrCodes: [],
      addrCodesSelected: [],
      regionData,
      codeToText,
      selectedOptions1: [],
      selectedOptions2: [],
      temp: {
        areaName: [],
        areaCode: []
      },
      areaName: [],
      areaCode: []
    };
  },
  methods: {
    // 获取省市区地址级联
    handleChange() {
      const thsAreaCode = this.$refs['cascaderAddr'].getCheckedNodes()[0];
      if (thsAreaCode) {
        this.addrCodes = thsAreaCode.path;
        this.addrCodesSelected = thsAreaCode.pathLabels;
        console.log(this.addrCodesSelected);
      } else {
        this.addrCodes = [];
        this.addrCodesSelected = [];
      }
    },
    handleChange1() {
      this.temp.areaName=[]
      this.temp.areaCode=[]
      if (this.selectedOptions1[0] != null && this.selectedOptions1[1] != null && this.selectedOptions1[2] != null) {
        for (let i = 0; i < 3; i++) {
          this.temp.areaName.push(this.codeToText[this.selectedOptions1[i]])
          this.temp.areaCode.push(this.selectedOptions1[i])
        }
      }
      console.log(this.temp)
    },
    handleChange2() {
      this.areaName=[]
      this.areaCode=[]
      if (this.selectedOptions2[0] != null && this.selectedOptions2[1] != null) {
        for (let i = 0; i < 2; i++) {
          this.areaName.push(this.codeToText[this.selectedOptions2[i]])
          this.areaCode.push(this.selectedOptions2[i])
        }
      }
    }
  }
};
</script>

<style scoped>
.cascader-container {
  max-width: 500px;
  margin: 20px auto;
  font-family: Arial, sans-serif;
  border: 1px solid #e0e0e0;
  border-radius: 8px;
  padding: 20px;
  background-color: #ffffff;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}

.title {
  font-size: 24px;
  font-weight: bold;
  margin-bottom: 16px;
  text-align: center;
}

.cascader {
  width: 100%;
}

.address-info {
  margin-top: 20px;
  border-top: 1px solid #e0e0e0;
  padding-top: 10px;
}

.info-item {
  margin: 5px 0;
  font-size: 16px;
}
</style>

这里为了方便查看效果,所以样式居中显示,样式根据自己需求修改,也可以封装成单独组件

第二步封装成单独组件

,需要选择到哪一级,就选择相应的组件 将地区选择器封装成三个独立的组件,可以使代码更具可复用性和可维护性。每个组件可以专注于处理不同层级的地区选择(乡镇、区和市)。以下是对代码的重构,包括三个独立的组件以及父组件的整合。

1. 地区选择器组件结构

  • TownSelector.vue:用于选择乡镇
  • DistrictSelector.vue:用于选择区
  • CitySelector.vue:用于选择市
  • RegionView.vue:父组件,整合上述三个选择器
TownSelector.vue
<template>
  <div class="cascader-container">
    <h2 class="title">到乡镇选择地区</h2>
    <el-cascader
      :options="options"
      :props="{ checkStrictly: true, value: 'code', label: 'name' }"
      v-model="selectedOptions"
      @change="handleChange"
      clearable
      class="cascader"
    >
      <template #default="{ node, data }">
        <span>{{ data.name }}</span>
        <span v-if="!node.isLeaf"> ({{ data.children.length }}) </span>
      </template>
    </el-cascader>
    <div class="address-info">
      <div class="info-item">地区编码:<strong>{{ addrCodes.join(',') }}</strong></div>
      <div class="info-item">地区:<strong>{{ addrCodesSelected.join('') }}</strong></div>
    </div>
  </div>
</template>

<script>
export default {
  props: {
    options: Array,
    selectedOptions: Array,
    addrCodes: Array,
    addrCodesSelected: Array,
    onChange: Function
  },
  methods: {
    handleChange() {
      const thsAreaCode = this.$refs.cascaderAddr.getCheckedNodes()[0];
      if (thsAreaCode) {
        this.addrCodes = thsAreaCode.path;
        this.addrCodesSelected = thsAreaCode.pathLabels;
        this.onChange(this.addrCodes, this.addrCodesSelected);
      } else {
        this.addrCodes = [];
        this.addrCodesSelected = [];
      }
    }
  }
};
</script>

<style scoped>
.cascader-container {
  max-width: 500px;
  margin: 20px auto;
}
.title {
  font-size: 24px;
  font-weight: bold;
  margin-bottom: 16px;
  text-align: center;
}
.cascader {
  width: 100%;
}
.address-info {
  margin-top: 20px;
  border-top: 1px solid #e0e0e0;
  padding-top: 10px;
}
.info-item {
  margin: 5px 0;
  font-size: 16px;
}
</style>
DistrictSelector.vue
<template>
  <div class="cascader-container">
    <h2 class="title">到区选择地区</h2>
    <el-cascader
      size="large"
      :options="regionData"
      v-model="selectedOptions"
      @change="handleChange"
      clearable
      class="cascader"
    >
    </el-cascader>
    <div class="address-info">
      <div class="info-item">地区编码:<strong>{{ temp.areaCode.join(',') }}</strong></div>
      <div class="info-item">地区:<strong>{{ temp.areaName.join('') }}</strong></div>
    </div>
  </div>
</template>

<script>
export default {
  props: {
    regionData: Array,
    selectedOptions: Array,
    codeToText: Object,
    onChange: Function
  },
  data() {
    return {
      temp: {
        areaName: [],
        areaCode: []
      }
    };
  },
  methods: {
    handleChange() {
      this.temp.areaName = [];
      this.temp.areaCode = [];
      if (this.selectedOptions.length > 0) {
        this.selectedOptions.forEach((code) => {
          this.temp.areaName.push(this.codeToText[code]);
          this.temp.areaCode.push(code);
        });
        this.onChange(this.temp.areaName, this.temp.areaCode);
      }
    }
  }
};
</script>

<style scoped>
.cascader-container {
  max-width: 500px;
  margin: 20px auto;
}
.title {
  font-size: 24px;
  font-weight: bold;
  margin-bottom: 16px;
  text-align: center;
}
.cascader {
  width: 100%;
}
.address-info {
  margin-top: 20px;
  border-top: 1px solid #e0e0e0;
  padding-top: 10px;
}
.info-item {
  margin: 5px 0;
  font-size: 16px;
}
</style>
CitySelector.vue
<template>
  <div class="cascader-container">
    <h2 class="title">到市选择地区</h2>
    <el-cascader
      size="large"
      :options="provinceAndCityData"
      v-model="selectedOptions"
      @change="handleChange"
      clearable
      class="cascader"
    >
    </el-cascader>
    <div class="address-info">
      <div class="info-item">地区编码:<strong>{{ areaCode.join(',') }}</strong></div>
      <div class="info-item">地区:<strong>{{ areaName.join('') }}</strong></div>
    </div>
  </div>
</template>

<script>
export default {
  props: {
    provinceAndCityData: Array,
    selectedOptions: Array,
    codeToText: Object,
    onChange: Function
  },
  data() {
    return {
      areaName: [],
      areaCode: []
    };
  },
  methods: {
    handleChange() {
      this.areaName = [];
      this.areaCode = [];
      if (this.selectedOptions.length > 0) {
        this.selectedOptions.forEach((code) => {
          this.areaName.push(this.codeToText[code]);
          this.areaCode.push(code);
        });
        this.onChange(this.areaName, this.areaCode);
      }
    }
  }
};
</script>

<style scoped>
.cascader-container {
  max-width: 500px;
  margin: 20px auto;
}
.title {
  font-size: 24px;
  font-weight: bold;
  margin-bottom: 16px;
  text-align: center;
}
.cascader {
  width: 100%;
}
.address-info {
  margin-top: 20px;
  border-top: 1px solid #e0e0e0;
  padding-top: 10px;
}
.info-item {
  margin: 5px 0;
  font-size: 16px;
}
</style>
RegionView.vue
<template>
  <div>
    <TownSelector
      :options="options"
      v-model="selectedOptions"
      :addrCodes="addrCodes"
      :addrCodesSelected="addrCodesSelected"
      :onChange="updateAddressInfo"
    />
    <DistrictSelector
      :regionData="regionData"
      v-model="selectedOptions1"
      :codeToText="codeToText"
      :onChange="updateDistrictInfo"
    />
    <CitySelector
      :provinceAndCityData="provinceAndCityData"
      v-model="selectedOptions2"
      :codeToText="codeToText"
      :onChange="updateCityInfo"
    />
  </div>
</template>

<script>
import TownSelector from './TownSelector.vue';
import DistrictSelector from './DistrictSelector.vue';
import CitySelector from './CitySelector.vue';
let pcas = require('@/assets/pcas-code.json');
import { regionData, provinceAndCityData, codeToText } from 'element-china-area-data';

export default {
  name: 'RegionView',
  components: {
    TownSelector,
    DistrictSelector,
    CitySelector
  },
  data() {
    return {
      options: pcas,
      provinceAndCityData,
      selectedOptions: [],
      addrCodes: [],
      addrCodesSelected: [],
      regionData,
      codeToText,
      selectedOptions1: [],
      selectedOptions2: []
    };
  },
  methods: {
    updateAddressInfo(codes, names) {
      this.addrCodes = codes;
      this.addrCodesSelected = names;
    },
    updateDistrictInfo(names, codes) {
      console.log('District Updated:', names, codes);
    },
    updateCityInfo(names, codes) {
      console.log('City Updated:', names, codes);
    }
  }
};
</script>

<style scoped>
/* 可选的全局样式 */
</style>
  • TownSelector.vue:处理乡镇的选择,获取编码和地区名称。
  • DistrictSelector.vue:处理区的选择,获取编码及地区名称。
  • CitySelector.vue:处理市的选择,获取编码和地区名称。
  • RegionView.vue:父级组件,整合三个选择器组件,并管理数据的传递和更新。

总结

将地区选择器拆分为不同的组件,使得逻辑更加清晰,代码结构更易于维护与扩展,符合组件化开发的最佳实践。这样也有助于将来根据需要复用某个选择器组件

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值