工作中经常会遇到需要前端实现省、市、区(县)的三级选择的场景,今天要介绍的是Vue和mint-ui结合实现的三级联动效果。

三级联动

我认为实现的难点在于mint-ui,Picker组件展示省市区三级联动数据上,建议先熟悉下mintUI的组件。

官方的解释:

 个人理解:

  • defaultIndex -> 默认展示数据的下标,默认序号为0
  • values -> 该数据选项的数据
  • className -> 数据展示的位置(数据本身的显示顺序)
  • textAlign ->  对齐方式
  • flex -> 将整个picker分成几份,他自己所占位置

附上官方文档地址picker组件 

[{
	flex: 1,
	defaultIndex: this.provinceIndex, //对应 slot 初始选中值
	values: Object.values(this.myaddress)[0],//对应 slot 的备选值数组
	className: 'slot1', //对应 slot 的类名
	textAlign: 'center' //数据对齐格式
},
{
	flex: 1,
	defaultIndex: this.cictyIndex,
	values: (Object.values(this.myaddress)[0])[this.provinceIndex].c,
	className: 'slot2',
	textAlign: 'center'
},
{
	flex: 1,
	defaultIndex: this.regionIndex,
	values: ((Object.values(this.myaddress)[0])[this.provinceIndex].c)[this.cictyIndex].a,
	className: 'slot3',
	textAlign: 'center'
}]

话不多说,直接上代码

1、准备省市区三级联动的数据

附上一部分省市区的json代码,有需要的可以和我联系

{
  "citylist": [{
    "p": "北京市",
    "c": [{
      "n": "市辖区",
      "a": [{
        "s": "东城区"
      }, {
        "s": "西城区"
      }, {
        "s": "朝阳区"
      }, {
        "s": "丰台区"
      }, {
        "s": "石景山区"
      }, {
        "s": "海淀区"
      }, {
        "s": "门头沟区"
      }, {
        "s": "房山区"
      }, {
        "s": "通州区"
      }, {
        "s": "顺义区"
      }, {
        "s": "昌平区"
      }, {
        "s": "大兴区"
      }, {
        "s": "怀柔区"
      }, {
        "s": "平谷区"
      }, {
        "s": "密云区"
      }, {
        "s": "延庆区"
      }]
    }]
  }, {
    "p": "天津市",
    "c": [{
      "n": "市辖区",
      "a": [{
        "s": "和平区"
      }, {
        "s": "河东区"
      }, {
        "s": "河西区"
      }, {
        "s": "南开区"
      }, {
        "s": "河北区"
      }, {
        "s": "红桥区"
      }, {
        "s": "东丽区"
      }, {
        "s": "西青区"
      }, {
        "s": "津南区"
      }, {
        "s": "北辰区"
      }, {
        "s": "武清区"
      }, {
        "s": "宝坻区"
      }, {
        "s": "滨海新区"
      }, {
        "s": "宁河区"
      }, {
        "s": "静海区"
      }, {
        "s": "蓟州区"
      }]
    }]
  }]
}

 2、在index.vue中引入省市区三级联动的子组件

//引入子组件
import selectArea from '@/areaselect/index.vue'

<select-area filed-label-text="幼儿园所在地区" :cictyArea.sync="userFormData.base.cictyArea"></select-area>

export default {
    components: {
        selectArea
    },
    data() {
        return {
            userFormData: {
                base: {
					cictyArea: '',
					detailAddress: '',
					insuredAdress: '',
				}
            }
        }
    }
}

3、实现省、市、区 三级联动的子组件

//省市区三级联动
<template>
	<div class="area-select">
		<div @click="getInsuredArea">
			<mt-field :label="filedText" :placeholder="'请选择' + filedText" v-model="basearea" disabled>
				<span>
					<img width="20px" :src="areaIcon" />
				</span>
			</mt-field>
		</div>
		<!-- 地区 -->
		<mt-popup v-model="insuredAreaVisiable" position="bottom" style="width:100%">
			<mt-picker :slots="insuredArea" value-key="p" @change="onAddressChange" ref="pickerArea" show-toolbar>
				<div class="picker-toolbar-box">
					<span class="picker-toolbar-ok" @click="confirmArea">确认</span>
				</div>
			</mt-picker>
		</mt-popup>
	</div>
</template>

划重点来了 

import myAddress from './tabs/cicty.json'
export default {
		data() {
			return {
				filedText: this.filedLabelText || '投保地区', //页面显示label
				insuredArea: [], //弹框显示数据
				basearea: this.cictyArea, //页面显示 省市区 例   河北省/石家庄市/市辖区
				chooseObj: { //选中的省市区
					province: '',
					cicty: '',
					region: ''
				},
				province: '', //省
				cicty: '', //市
				region: '', //区
				defaultIndex: false,
				provinceIndex: 0, //所选省下标
				cictyIndex: 0, //所选市下标
				regionIndex: 0, //所选区下标
				insuredAreaVisiable: false, //弹框显隐控制
				areaIcon: require('@/assets/svg/location.svg'),
				handler: function(e) {e.preventDefault()} //阻止默认操作
			}
		},
        props: {
			cictyArea: {
				type: String,
				default: ''
			},
			filedLabelText: {
				type: String,
				default: ''
			}
		},
        mounted() {
			let address = JSON.stringify(myAddress).replace(/n/g, 'p')
			address = address.replace(/s/g, 'p')
			address = address.replace(/市辖区/, '市辖区')
			this.myaddress = JSON.parse(address)
			this.insuredArea = [{
					flex: 1,
					defaultIndex: this.provinceIndex,
					values: Object.values(this.myaddress)[0],
					className: 'slot1',
					textAlign: 'center'
				},
				{
					flex: 1,
					defaultIndex: this.cictyIndex,
					values: (Object.values(this.myaddress)[0])[this.provinceIndex].c,
					className: 'slot2',
					textAlign: 'center'
				},
				{
					flex: 1,
					defaultIndex: this.regionIndex,
					values: ((Object.values(this.myaddress)[0])[this.provinceIndex].c)[this.cictyIndex].a,
					className: 'slot3',
					textAlign: 'center'
				}
			]

		},
		methods: {
			// 弹层出现
			closeTouch() {
				document.getElementsByTagName("body")[0].addEventListener('touchmove', this.handler,{passive:false});
			},

			// 弹层关闭
			openTouch() {
				document.getElementsByTagName("body")[0].removeEventListener('touchmove',this.handler,{passive:false});
			},

			onAddressChange(picker, values) {
				if (values[0]) {
					picker.setSlotValues(1, values[0].c)
					picker.setSlotValues(2, values[1].a)
				}

				if (values && values.length > 0) {
					this.province = values[0].p
					this.cicty = values[1].p
					this.region = values[2].p
				}
			},

			remeberIndex(province, cicty, region) {
				for (let i = 0; i < (Object.values(this.myaddress)[0]).length; i++) {
					if (province === (Object.values(this.myaddress)[0])[i].p) {
						this.provinceIndex = i
					}
				}

				for (let i = 0; i < ((Object.values(this.myaddress)[0])[this.provinceIndex].c).length; i++) {
					if (cicty === ((Object.values(this.myaddress)[0])[this.provinceIndex].c)[i].p) {
						this.cictyIndex = i
					}
				}

				for (let i = 0; i < (((Object.values(this.myaddress)[0])[this.provinceIndex].c)[this.cictyIndex].a)
					.length; i++) {
					if (region === (((Object.values(this.myaddress)[0])[this.provinceIndex].c)[this.cictyIndex].a)[i].p) {
						this.regionIndex = i
					}
				}
			},

			getInsuredArea() {
				this.closeTouch()
				this.insuredAreaVisiable = true
				this.defaultIndex = false
			},
			// 地区
			confirmArea() {
				if(!this.province) {
					this.province = (Object.values(this.myaddress)[0])[0].p
					this.cicty = ((Object.values(this.myaddress)[0])[this.provinceIndex].c)[0].p
					this.region = (((Object.values(this.myaddress)[0])[this.provinceIndex].c)[this.cictyIndex].a)[0].p
				}
				this.chooseObj.province = this.province
				this.chooseObj.cicty = this.cicty
				this.chooseObj.region = this.region
				this.basearea = this.chooseObj.province + '/' + this.chooseObj.cicty.trim() + '/' + this.chooseObj.region
				this.insuredAreaVisiable = false
				this.openTouch()
				this.defaultIndex = true
				this.$emit('update:cictyArea', this.basearea)
			}
		}
}

完整代码上传到资源了,有需要的自行下载

Logo

前往低代码交流专区

更多推荐