uniapp小程序级联选择器

682 阅读1分钟

PS:找了很多地方,没找到适用三端小程序的省市区级联选择器的,所以自己写了一个,放这里大家需要可以拿去改改用

  • ✔️ 微信
  • ✔️ 支付宝小程序
  • ✔️ h5

uniapp-vue2 , lodash

效果

123.gif

使用:

	<my-address-picker
            :visible.sync="addressPicker_visible"
            :activated="['广东省','深圳市','南山区']"
            @confirm="addressChange"
	/>

代码如下:

地址可以先用这个数据,然后按需二开,raw.githubusercontent.com/tengyuanOas…


// my-address-picker.vue

<template>
	<view class="address-picker-popup">
		<uni-popup
			mask-background-color="rgba(0, 0, 0, .8)"
			ref="detailPop"
			type="bottom"
			background-color="#fff"
		>
			<scroll-view class="popup popup-content" scroll-y>
				<view class="popup-header">
					<view class="font-16 font-bold pop-title">选择地址</view>
					<view class="pop-close" @click="close" />
				</view>
				<view class="font-14 popup-main">
					<picker-view :value="activeIndex" @change="bindChange" class="picker-view">
						<picker-view-column class="picker-view-column">
							<view class="picker-view-item" v-for="(item, index) in provinceList" :key="index">
								{{ item.label }}
							</view>
						</picker-view-column>
						<picker-view-column class="picker-view-column">
							<view class="picker-view-item" v-for="(item, index) in cityList" :key="index">
								{{ item.label }}
							</view>
						</picker-view-column>
						<picker-view-column class="picker-view-column">
							<view class="picker-view-item" v-for="(item, index) in countyList" :key="index">
								{{ item.label }}
							</view>
						</picker-view-column>
					</picker-view>

					<view class="footer">
						<view class="footer-item" @click="reset">清空</view>
						<view class="footer-item" @click="confirm">确定</view>
					</view>
				</view>
			</scroll-view>
		</uni-popup>
	</view>
</template>

<script>
	import { getSysConstant } from '@/api';

	import find from 'lodash/find';
	const app = getApp();
	export default {
		label: 'DetailPopup',
		components: {},
		props: {
			visible: {
				required: true,
				default: false
			},
			activated: {
				required: true,
				type: Array,
				default: () => []
			}
		},
		watch: {
			visible(newVal) {
				if (newVal) {
					this.init();
					this.$refs.detailPop.open();
				} else {
					this.$refs.detailPop.close();
				}
			}
		},
		computed: {
			cityList() {
				return this.provinceInfo?.children ?? [];
			},
			countyList() {
				return this.cityInfo?.children ?? [];
			}
		},
		data() {
			return {
				activeIndex: [0, 0, 0],
				addressData: [],
				provinceInfo: {},
				cityInfo: {},
				countyInfo: {},
				provinceList: []
			};
		},
		created() {
			this.loadAddressInfo();
		},
		methods: {
			async loadAddressInfo() {
				// 获取级联地址数据
				this.provinceList = [];
			},
			init(list = this.provinceList) {
				if (this.activated?.length < 3) {
					this.activeIndex = [0, 0, 0];
					this.provinceInfo = list[0];
					this.cityInfo = list[0]?.children[0] ?? {};
					this.countyInfo = list[0]?.children[0]?.children[0] ?? {};
					return;
				}
                                let p_idx=0,c_idx=0,a_idx=0;
				const [province = '', city = '', county = ''] = this.activated;
				const provinceInfo = find(list, (info, index) => {
					const bol = info.label === province;
					if (bol) p_idx = index;
					return bol;
				});
				const cityInfo = find(provinceInfo?.children, (info, index) => {
					const bol = info.label === city;
					if (bol) c_idx = index;
					return bol;
				});
				const countyInfo = find(cityInfo?.children, (info, index) => {
					const bol = info.label === county;
					if (bol) a_idx = index;
					return bol;
				});

				this.provinceInfo = provinceInfo;
				this.cityInfo = cityInfo;
				this.countyInfo = countyInfo;
				this.activeIndex = [p_idx, c_idx, a_idx];
			},
			bindChange(e) {
				const p_idx = e.detail.value[0];
				const current_province = this.provinceList[p_idx];
				let c_idx = e.detail.value[1];
				let a_idx = e.detail.value[2];
				if (this.provinceInfo.label !== current_province.label) {
					c_idx = 0;
					a_idx = 0;
				}
				const current_cityList = current_province?.children ?? [];
				const current_cityInfo = current_cityList[c_idx] ?? {};
				if (current_cityInfo.label !== this.cityInfo.label) {
					a_idx = 0;
				}
				const current_countyList = current_cityInfo?.children ?? [];
				const current_countyInfo = current_countyList[a_idx] ?? {};

				this.provinceInfo = current_province;
				this.cityInfo = current_cityInfo;
				this.countyInfo = current_countyInfo;
				this.activeIndex = [p_idx, c_idx, a_idx];
			},
			close() {
				this.$emit('update:visible', false);
			},
                        reset() {
				const params = {
					detail: {
						value: [0, 0, 0]
					}
				};
				this.bindChange(params);
			},
			confirm() {
				const result = {
					province: this.provinceInfo?.label,
					city: this.cityInfo?.label,
					county: this.countyInfo?.label
				};
				uni.showToast({
					title: '已选地址:' + JSON.stringify(result)
				});
				// this.$emit('confirm', result);
				// this.close();
			},
		}
	};
</script>

<style scoped lang="scss">
	.picker-view {
		width: 100%;
		height: 500rpx;
		display: flex;
		justify-content: space-between;
		.picker-view-column {
			width: 200rpx;
			margin: 0 20rpx;
			.picker-view-item {
				width: 100%;
				text-align: center;
				display: flex;
				justify-content: center;
				align-items: center;
			}
		}
	}
	.footer {
		width: 100%;
		display: flex;
		justify-content: space-between;
		align-items: center;
		padding: 40rpx 80rpx 20rpx;
		border-top: 1px solid rgba($color: #ddd, $alpha: 0.5);
		.footer-item {
			font-size: 28rpx;
		}
	}
</style>