uniapp 三级联动选择省市区

// 接口数据格式:
{
	"code": 1000,
	"msg": "成功",
	"data": {
		"list": [{
			"citycode": "",
			"adcode": "410000",
			"name": "河南省",
			"center": "113.753094,34.767052",
			"level": "province",
			"districts": [{
				"citycode": "0379",
				"adcode": "410300",
				"name": "洛阳市",
				"center": "112.453895,34.619702",
				"level": "city",
				"districts": [{
					"citycode": "0379",
					"adcode": "410323",
					"name": "新安县",
					"center": "112.13246,34.728909",
					"level": "district",
					"districts": []
				}, {
					"citycode": "0379",
					"adcode": "410327",
					"name": "宜阳县",
					"center": "112.179187,34.51462",
					"level": "district",
					"districts": []
				}, {
					"citycode": "0379",
					"adcode": "410328",
					"name": "洛宁县",
					"center": "111.652958,34.389371",
					"level": "district",
					"districts": []
				}]
			}, {
				"citycode": "0398",
				"adcode": "411200",
				"name": "三门峡市",
				"center": "111.200482,34.773196",
				"level": "city",
				"districts": [{
					"citycode": "0398",
					"adcode": "411202",
					"name": "湖滨区",
					"center": "111.188552,34.771296",
					"level": "district",
					"districts": []
				}, {
					"citycode": "0398",
					"adcode": "411221",
					"name": "渑池县",
					"center": "111.761753,34.767937",
					"level": "district",
					"districts": []
				}, {
					"citycode": "0398",
					"adcode": "411281",
					"name": "义马市",
					"center": "111.874726,34.747563",
					"level": "district",
					"districts": []
				}]
			}, {
				"citycode": "0374",
				"adcode": "411000",
				"name": "许昌市",
				"center": "113.852004,34.03732",
				"level": "city",
				"districts": [{
					"citycode": "0374",
					"adcode": "411003",
					"name": "建安区",
					"center": "113.822869,34.124729",
					"level": "district",
					"districts": []
				}, {
					"citycode": "0374",
					"adcode": "411002",
					"name": "魏都区",
					"center": "113.830826,34.047189",
					"level": "district",
					"districts": []
				}, {
					"citycode": "0374",
					"adcode": "411024",
					"name": "鄢陵县",
					"center": "114.177329,34.102985",
					"level": "district",
					"districts": []
				}]
			}]
		}, {
			"citycode": "",
			"adcode": "440000",
			"name": "广东省",
			"center": "113.266887,23.133306",
			"level": "province",
			"districts": [{
				"citycode": "0757",
				"adcode": "440600",
				"name": "佛山市",
				"center": "113.121586,23.021351",
				"level": "city",
				"districts": [{
					"citycode": "0757",
					"adcode": "440608",
					"name": "高明区",
					"center": "112.892573,22.900047",
					"level": "district",
					"districts": []
				}, {
					"citycode": "0757",
					"adcode": "440607",
					"name": "三水区",
					"center": "112.897271,23.156675",
					"level": "district",
					"districts": []
				}, {
					"citycode": "0757",
					"adcode": "440605",
					"name": "南海区",
					"center": "113.143246,23.028875",
					"level": "district",
					"districts": []
				}]
			}, {
				"citycode": "0758",
				"adcode": "441200",
				"name": "肇庆市",
				"center": "112.465245,23.047747",
				"level": "city",
				"districts": [{
					"citycode": "0758",
					"adcode": "441225",
					"name": "封开县",
					"center": "111.512177,23.423928",
					"level": "district",
					"districts": []
				}, {
					"citycode": "0758",
					"adcode": "441224",
					"name": "怀集县",
					"center": "112.166908,23.920806",
					"level": "district",
					"districts": []
				}, {
					"citycode": "0758",
					"adcode": "441223",
					"name": "广宁县",
					"center": "112.440694,23.634808",
					"level": "district",
					"districts": []
				}]
			}]
		},
	}
}
在components 文件夹下新建cus-city-picker目录,新建cus-city-picker.vue页面
<template>
	<view class="pupop">
		<view class="popup-box" :animation="animationData">
			<view class="pupop-btn">
				<view @tap="onCancel">取消</view>
				<view @tap="onConfirm" style="color: #2979ff;">确定</view>
			</view>
			<picker-view :value="value" :indicator-style="indicatorStyle" @change="onBindChange" class="picker-view">
				<picker-view-column>
					<view class="item" v-for="(item,index) in provinceList" :key="index">{{item.name}}</view>
				</picker-view-column>
				<picker-view-column>
					<view class="item" v-for="(item,index) in cityList" :key="index">{{item.name}}</view>
				</picker-view-column>
				<picker-view-column v-if="column == 3">
					<view class="item" v-for="(item,index) in areaList" :key="index">{{item.name}}</view>
				</picker-view-column>
			</picker-view>
		</view>
		<view @tap="onClose" @touchmove.stop.prevent :class="visible ? 'pupop-model' : 'pupop-models'"></view>
	</view>
</template>

<script>
	export default {
		data() {
			return {
				value: [],
				provinceList: [],
				cityList: [],
				areaList: [],
				indicatorStyle: `height: 50px;`,
				provinceIndex: 0,
				cityIndex: 0,
				areaIndex: 0,
				animationData: {}
			}
		},
		props: {
			addressList: {
				type: Array,
				default: []
			},
			column: {
				type: Number,
				default: 3
			},
			defaultValue: {
				default: () => ''
			},
			visible: {
				type: Boolean,
				default: () => false
			},
			maskCloseAble: {
				type: Boolean,
				default: () => true
			},
		},
		watch: {
			addressList(val) {
				this.init()
			},
			visible(val) {
				this.onChangeActive()
			},
		},
		methods: {
			init() {
				var provinceList = []
				this.addressList.filter(item => {
					provinceList.push({
						adcode: item.adcode,
						name: item.name
					})
				})
				this.provinceList = [...provinceList]
				if (!this.defaultValue) {
					this.cityList = this.addressList[0].districts
					this.areaList = this.addressList[0].districts[0].districts
				} else {
					if (Array.isArray(this.defaultValue) && this.defaultValue.length >= 2) {
						var province = this.defaultValue[0]
						var city = this.defaultValue[1]
						this.provinceIndex = this.addressList.findIndex(obj => {
							return obj.name == province
						})
						this.provinceIndex = this.provinceIndex >= 0 ? this.provinceIndex : 0;

						this.cityList = this.addressList[this.provinceIndex].districts
						this.cityIndex = this.cityList.findIndex(obj => {
							return obj.name == city
						})
						this.cityIndex = this.cityIndex >= 0 ? this.cityIndex : 0;
						
						this.areaList = this.cityList[this.cityIndex].districts
						if (this.defaultValue.length > 2) {
							this.areaIndex = this.areaList.findIndex(obj => {
								return obj.name == this.defaultValue[2]
							})
						}
						this.areaIndex = this.areaIndex >= 0 ? this.areaIndex : 0;
						
						this.$nextTick(() => {
							if (this.column == 3) {
								this.value = JSON.parse(JSON.stringify([this.provinceIndex, this.cityIndex, this
									.areaIndex
								]))
							} else if (this.column == 2) {
								this.value = JSON.parse(JSON.stringify([this.provinceIndex, this.cityIndex]))
							}
						})
					} else if (/^\d{6}$/.test(this.defaultValue)) {
						var province = this.defaultValue.substr(0, 2)
						var city = this.defaultValue.substr(0, 4);
						this.provinceIndex = this.addressList.findIndex(obj => {
							return obj.adcode == province
						})
						this.provinceIndex = this.provinceIndex >= 0 ? this.provinceIndex : 0;
						
						this.cityList = this.addressList[this.provinceIndex].districts
						this.cityIndex = this.cityList.findIndex(obj => {
							return obj.adcode == city
						})
						this.cityIndex = this.cityIndex >= 0 ? this.cityIndex : 0;
						
						this.areaList = this.cityList[this.cityIndex].districts
						this.areaIndex = this.areaList.findIndex(obj => {
							return obj.adcode == this.defaultValue
						})
						this.areaIndex = this.areaIndex >= 0 ? this.areaIndex : 0;
						
						this.$nextTick(() => {
							if (this.column == 3) {
								this.value = JSON.parse(JSON.stringify([this.provinceIndex, this.cityIndex, this
									.areaIndex
								]))
							} else if (this.column == 2) {
								this.value = JSON.parse(JSON.stringify([this.provinceIndex, this.cityIndex]))
							}
						})
					} else {
						uni.showToast({
							title: '地区编码格式不正确',
							icon: 'none'
						}) 
					}
				}
				this.onChangeActive()
			},
			onConfirm() {
				if (this.column == 3) {
					this.$emit('confirm', {
						adcode: this.addressList[this.provinceIndex].districts[this.cityIndex].districts[this
								.areaIndex]
							.adcode,
						name: this.addressList[this.provinceIndex].name + this.addressList[this.provinceIndex]
							.districts[this
								.cityIndex].name + this.addressList[this.provinceIndex].districts[this.cityIndex]
							.districts[this.areaIndex].name,
						provinceName: this.addressList[this.provinceIndex].name,
						cityName: this.addressList[this.provinceIndex].districts[this.cityIndex].name,
						areaName: this.addressList[this.provinceIndex].districts[this.cityIndex].districts[this
							.areaIndex].name
					})
				} else if (this.column == 2) {
					this.$emit('confirm', {
						adcode: this.addressList[this.provinceIndex].districts[this.cityIndex].districts[this
								.areaIndex]
							.adcode.substring(0, 4) + '00',
						name: this.addressList[this.provinceIndex].name + this.addressList[this.provinceIndex]
							.districts[this
								.cityIndex].name,
						provinceName: this.addressList[this.provinceIndex].name,
						cityName: this.addressList[this.provinceIndex].districts[this.cityIndex].name
					})
				} else {
					uni.showToast({
						title: '目前column只能传2和3',
						icon: 'none'
					})
				}
			},
			onCancel() {
				this.$emit('cancel')
			},
			// 动画
			onChangeActive() {
				var active = '-315px'
				if (this.visible) {
					active = 0
				}
				var animation = uni.createAnimation({
					duration: 400,
					timingFunction: 'linear'
				})
				animation.bottom(active).step()
				this.animationData = animation.export()
			},
			onBindChange(e) {
				e.detail.value[0] = e.detail.value[0] || 0
				e.detail.value[1] = e.detail.value[1] || 0
				e.detail.value[2] = e.detail.value[2] || 0
				if (e.detail.value[0] != this.provinceIndex) {
					this.onProvinceChange(e.detail.value[0])
				} else if (e.detail.value[1] != this.cityIndex) {
					this.onCityChange(e.detail.value[1])
				} else if (e.detail.value[2] != this.areaIndex) {
					this.onAreaChange(e.detail.value[2])
				}
			},
			// 监听第一列变化
			onProvinceChange(e) {
				this.provinceIndex = e
				this.cityIndex = 0
				this.areaIndex = 0
				this.value = [...[e, 0, 0]]
				this.cityList = this.addressList[e].districts
				this.areaList = this.addressList[e].districts[0].districts
			},
			// 监听第二列变化
			onCityChange(e) {
				this.cityIndex = e
				this.areaIndex = 0
				this.value = [...[this.provinceIndex, e, 0]]
				this.cityList = this.addressList[this.provinceIndex].districts
				this.areaList = this.addressList[this.provinceIndex].districts[e].districts
			},
			// 监听第三列变化
			onAreaChange(e) {
				this.areaIndex = e
			},
			// 点击模态框
			onClose() {
				if (this.maskCloseAble) {
					this.onCancel()
				}
			}
		}
	}
</script>

<style scoped lang="scss">
	.pupop {
		.popup-box {
			position: fixed;
			left: 0;
			bottom: -315px;
			z-index: 99999;
			background: #fff;
			padding-bottom: 50px;

			.pupop-btn {
				height: 40px;
				display: flex;
				align-items: center;
				padding: 0 30upx;
				justify-content: space-between;
			}
		}

		.pupop-model {
			position: fixed;
			left: 0;
			top: 0;
			width: 100%;
			height: 100%;
			z-index: 9999;
			background: rgba(0, 0, 0, .5);
		}

		.pupop-models {
			display: none;
		}

		.picker-view {
			width: 750rpx;
			height: 225px;
			margin-top: 20rpx;
		}

		.item {
			height: 50px;
			align-items: center;
			justify-content: center;
			text-align: center;
			line-height: 50px;
		}
	}
</style>
在index.vue页面调用组件
<template>
	<view class="w-100">
		<view class="w-100 cus-flex-start-j">
			<view style="width: 150rpx;font-size: 32rpx;font-weight: bold;">所在地区</view>
			<view @click="onChooseCity">
				<u-input v-model="district" border="none" placeholder="请选择" readonly customStyle="margin-top:0rpx;"
					suffixIcon="arrow-down" suffixIconStyle="color: #D7D7D7"></u-input>
			</view>
		</view>
		<!-- 选择所在地区 -->
		<cityPicker :column="3" :default-value="cityInfo.defaultValue" :addressList='addressList'
			:mask-close-able="true" :visible="cityInfo.visible" @confirm="onConfirmCity" @cancel="onCancelCity">
		</cityPicker>
	</view>
</template>

<script>
	import api from "@/utils/api.js";
	import cityPicker from '@/subpackages/components/cus-city-picker-http/cus-city-picker-http'
	export default {
		components: {
			cityPicker
		},
		data() {
			return {
				addressList: [],
				district: '', //地区:省,市,区(用,分割)
				cityInfo: {
					visible: false,
					defaultValue: '',
				},
			}
		},
		created() {
			this.getCitys();
		},
		methods: {
			//获取城市列表
			getCitys() {
				api.getCitys({
					data: {
						type: 'district'
					}
				}).then(res => {
					this.addressList = res.data.list
				});
			},
			//选择城市
			onChooseCity() {
				this.cityInfo.visible = true
			},
			onConfirmCity(val) {
				this.district = val.provinceName + ',' + val.cityName + ',' + val.areaName;
				this.cityInfo.visible = false;
			},
			onCancelCity() {
				this.cityInfo.visible = false;
				if (this.district == '') {
					console.log("请选择所在地区")
				}
			},
		},
	}
</script>

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值