HR招骋微信小程序_基于Vue+ElementUI的省市区地点选

基于Vue+ElementUI的省市区地址选择通用组件       这篇文章主要介绍了基于Vue+ElementUI的省市区地址选择通用组件,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

一、缘由

在项目开发过程中,有一个需求是省市区地址选择的功能,一开始想的是直接使用静态地址资源库本地打包,但这种方式不方便维护,于是放弃。后来又想直接让后台返回全部地址数据,然后使用级联选择器进行选择,但发现数据传输量有点大且处理过程耗时,于是又摒弃了这种方法。最后还是决定采用异步的方式进行省市区地址选择,即先查询省份列表,然后根据选择的省份code查询城市列表,最后根据选择的城市列表获取区/县列表,最终根据应用场景不同,给出了两种实现方案。

其中后台总共需要提供4个接口,一个查询所有省份的接口,一个根据省份code查询其下所有城市的接口,一个根据城市code查询其下所有区/县的接口,以及一个根据地址code转换成省市区三个code值的接口。

// 本人项目中使用的四个接口
`${this.API.province}/${countryCode}` // 根据国家code查询省份列表,中国固定为156,可以拓展
`${this.API.city }/${provinceCode}` // 根据省份code查询城市列表
`${this.API.area}/${cityCode}` // 根据城市code查询区/县列表
`${this.API.addressCode}/${addressCode}` // 地址code转换为省市区code

二、基于el-cascader 级联选择器的单选择框实现方案

 template 
 el-row 
 el-cascader
 size="small"
 :options="city.options"
 :pro凡科抠图="pro凡科抠图"
 v-model="cityValue"
 @active-item-change="handleItemChange"
 @change="cityChange" 
 /el-cascader 
 /el-row 
 /template 
 script 
export default {
 name: 'addressSelector',
 pro凡科抠图: {
 areaCode: null
 model: {
 prop: 'areaCode',
 event: 'cityChange'
 data () {
 return {
 // 所在省市
 city: {
 obj: {},
 options: []
 pro凡科抠图: { // 级联选择器的属性配置
 value: 'value',
 children: 'cities',
 checkStrictly: true
 cityValue: [], // 城市代码
 computed: {
 created () {
 this._initData()
 mounted () {
 methods: {
 _initData () {
 this.$http({
 method: 'get',
 url: this.API.province + '/156' // 中国
 }).then(res = {
 this.city.options = res.data.body.map(item = { // 所在省市
 return {
 value: item.provinceCode,
 label: item.provinceName,
 cities: []
 getCodeByAreaCode (code) {
 if (code == undefined) return false
 this.$http({
 method: 'get',
 url: this.API.addressCode + '/' + code
 .then(res = {
 if (res.data.code === this.API.SUCCESS) {
 let provinceCode = res.data.body.provinceCode
 let cityCode = res.data.body.cityCode
 let areaCode = res.data.body.areaCode
 this.cityValue = [provinceCode, cityCode, areaCode]
 this.handleItemChange([provinceCode, cityCode])
 .finally(res = {
 handleItemChange (value) {
 let a = (item) = {
 this.$http({
 method: 'get',
 url: this.API.city + '/' + value[0],
 }).then(res = {
 item.cities = res.data.body.map(ite = {
 return {
 value: ite.cityCode,
 label: ite.cityName,
 cities: []
 if(value.length === 2){ // 如果传入的value.length===2 先执行的a(),说明是传入了areaCode,需要初始化多选框
 b(item)
 }).finally(_ = {
 let b = (item) = {
 if (value.length === 2) {
 item.cities.find(ite = {
 if (ite.value === value[1]) {
 if (!ite.cities.length) {
 this.$http({
 method: 'get',
 url: this.API.area + '/' + value[1]
 }).then(res = {
 ite.cities = res.data.body.map(ite = {
 return {
 value: ite.areaCode,
 label: ite.areaName,
 }).finally(_ = {
 this.city.options.find(item = {
 if (item.value === value[0]) {
 if (item.cities.length) {
 b(item)
 } else {
 a(item)
 return true
 getCityCode () {
 return this.cityValue[2]
 reset () {
 this.cityValue = []
 cityChange (value) {
 if (value.length === 3) {
 this.$emit('cityChange', value[2])
 } else {
 this.$emit('cityChange', null)
 watch: {
 areaCode: {
 deep: true,
 immediate: true,
 handler (newVal) {
 if (newVal) {
 this.getCodeByAreaCode(newVal)
 } else {
 this.$nextTick(() = {
 this.reset()
 /script 
 style lang="less" scoped 
 /style 

最终效果如下(动图):

截图:

三、基于el-select选择器的多选择框实现方案

lt;template 
 div id="addressHorizontalSelect" 
 el-row 
 el-col
 :span="span" 
 el-select
 size="small"
 v-model="provinceCode"
 @focus="getProvinces"
 @change="changeProvince"
 :placeholder="$t('省')"
 filterable 
 el-option
 v-for="item in provinceList"
 :key="item.provinceCode"
 :label="item.provinceName"
 :value="item.provinceCode" 
 /el-option 
 /el-select 
 /el-col 
 el-col
 :span="span"
 v-if="!hideCity" 
 el-select
 size="small"
 v-model="cityCode"
 @focus="getCities"
 @change="changeCity"
 :placeholder="$t('市')"
 filterable 
 el-option
 v-for="item in cityList"
 :key="item.cityCode"
 :label="item.cityName"
 :value="item.cityCode" 
 /el-option 
 /el-select 
 /el-col 
 el-col
 :span="span"
 v-if="!hideCity !hideArea" 
 el-select
 size="small"
 v-model="areaCode"
 @focus="getAreas"
 @change="changeArea"
 :placeholder="$t('区/县')"
 filterable 
 el-option
 v-for="item in areaList"
 :key="item.areaCode"
 :label="item.areaName"
 :value="item.areaCode" 
 /el-option 
 /el-select 
 /el-col 
 /el-row 
 /div 
 /template 
 script 
export default {
 name: 'addressHorizontalSelect',
 components: {},
 pro凡科抠图: {
 hideCity: { // 隐藏市
 type: Boolean,
 default: false
 hideArea: { // 隐藏区/县
 type: Boolean,
 default: false
 addressCode: null // 地址编码
 model: {
 prop: 'addressCode',
 event: 'addressSelect'
 data() {
 return {
 provinceList: [], // 省份列表
 cityList: [], // 城市列表
 areaList: [], // 区/县列表
 provinceCode: '', // 省份编码
 cityCode: '', // 城市编码
 areaCode: '', // 区/县编码
 cityFlag: false, // 避免重复请求的标志
 provinceFlag: false,
 areaFlag: false
 computed: {
 span () {
 if (this.hideCity) {
 return 24
 if (this.hideArea) {
 return 12
 return 8
 watch: {
 created () {
 this.getProvinces()
 methods: {
 * 获取数据
 * @param {Array} array 列表
 * @param {String} url 请求url
 * @param {String} code 编码(上一级编码)
 fetchData (array, url, code) {
 this.$http({
 method: 'get',
 url: url + '/' + code
 .then(res = {
 if (res.data.code === this.API.SUCCESS) {
 let body = res.data.body || []
 array.splice(0, array.length, ...body)
 .catch(err = {
 console.log(err)
 .finally(res = {
 // 根据国家编码获取省份列表
 getProvinces () {
 if (this.provinceFlag) {
 return
 this.fetchData(this.provinceList, this.API.province, 156)
 this.provinceFlag = true
 // 省份修改,拉取对应城市列表
 changeProvince (val) {
 this.fetchData(this.cityList, this.API.city, this.provinceCode)
 this.cityFlag = true
 this.cityCode = ''
 this.areaCode = ''
 this.$emit('addressSelect', val)
 // 根据省份编码获取城市列表
 getCities () {
 if (this.cityFlag) {
 return
 if (this.provinceCode) {
 this.fetchData(this.cityList, this.API.city, this.provinceCode)
 this.cityFlag = true
 // 城市修改,拉取对应区域列表
 changeCity (val) {
 this.fetchData(this.areaList, this.API.area, this.cityCode)
 this.areaFlag = true
 this.areaCode = ''
 this.$emit('addressSelect', val)
 // 根据城市编码获取区域列表
 getAreas () {
 if (this.areaFlag) {
 return
 if (this.cityCode) {
 this.fetchData(this.areaList, this.API.area, this.cityCode)
 // 区域修改
 changeArea (val) {
 this.$emit('addressSelect', val)
 // 重置省市区/县编码
 reset () {
 this.provinceCode = '',
 this.cityCode = '',
 this.areaCode = ''
 // 地址编码转换成省市区列表
 addressCodeToList (addressCode) {
 if (!addressCode) return false
 this.$http({
 method: 'get',
 url: this.API.addressCode + '/' + addressCode
 .then(res = {
 let data = res.data.body
 if (!data) return
 if (data.provinceCode) {
 this.provinceCode = data.provinceCode
 this.fetchData(this.cityList, this.API.city, this.provinceCode)
 } else if (data.cityCode) {
 this.cityCode = data.cityCode
 this.fetchData(this.areaList, this.API.area, this.cityCode)
 } else if (data.areaCode) {
 this.areaCode = data.areaCode
 .finally(res = {
 watch: {
 addressCode: {
 deep: true,
 immediate: true,
 handler (newVal) {
 if (newVal) {
 this.addressCodeToList(newVal)
 } else {
 this.$nextTick(() = {
 this.reset()
 /script 
 style lang="less" scoped 
 /style 

实现效果如下(动图):

四、总结

两个组件都实现了双向绑定,根据场景不同可以使用不同的组件,如果读者有需求,根据自己的接口和场景进行修改即可。

当拓展至大洲-国家-省-市-区-街道等时,第一种级联选择器的方案就会暴露出拓展性较差的问题,随着层级加深,数据结构会变得复杂,而第二种方案明显可拓展性更强




扫描二维码分享到微信