uniapp实现picker三级数据连选弹框组件(适用省市区

875 阅读3分钟

uniapp实现picker三级数据连选弹框组件,支持省市区,支持异步props数据,拿去改吧改吧样式就能直接用

(vue3组合式api,使用uni-popup嵌套picker-view实现,传入)

效果展示:

image.png

官方链接 picker-view | uni-app官网

官方链接uni-popup 弹出层 | uni-app官网

代码:每种情况都判断了

<template>
	<uni-popup ref="popup" type="bottom" @change="popupChange">
		<view class="myPickerBox">
			<view class="uni-padding-wrap">
				<view class="left" @click="()=>(closePopup())">
					取消
				</view>
				<view class="center">
					<image class="center_img" src="../static/image/Icons/Dec@2x.png" mode=""></image>
					<view class="center_tital">
						{{tital}}
					</view>
					<image class="center_img" src="../static/image/Icons/Dec@2x.png" mode=""></image>
				</view>
				<view class="right" @click="()=>(closePopup(true))">
					保存
				</view>
			</view>
			<view class="box_hide">
				<picker-view :value="indexArr" @change="bindChange" :immediate-change="true" class="pickerView"
					indicator-class="indicator" mask-class="mask">
					<picker-view-column>
						<view class="item" v-for="(item,index) in list" :key="item.value">{{item.label}}</view>
					</picker-view-column>
					<picker-view-column v-if="list2 && list2.length!=0">
						<view class="item" v-for="(item,index) in list2" :key="item.value">{{item.label}}</view>
					</picker-view-column>
					<picker-view-column v-if="list3 && list3.length!=0">
						<view class="item" v-for="(item,index) in list3" :key="item.value">{{item.label}}</view>
					</picker-view-column>
				</picker-view>
			</view>
		</view>
	</uni-popup>
</template>

<script setup>
	import {
		onLoad,
		onShow,
		onReady,
	} from "@dcloudio/uni-app"
	import {
		isRef,
		nextTick,
		ref,
		toRefs,
		watch,
	} from 'vue';
	const popup = ref(null)
	const props = defineProps({
		list: {
			type: Array,
			default: () => []
		},
		tital: {
			type: String,
			required: true
		},
		isTab: { //当前是否是tab页面
			type: Boolean,
			default: () => false
		},
	})
	const {
		list,
	} = toRefs(props)
	const indexArr = ref([])
	const emit = defineEmits(['setIndexList'])
	const list2 = ref([])
	const list3 = ref([])
	onReady(() => {})
	const bindChange = (e) => {
		const [index1, index2, index3] = e.detail.value
		// 根据传入数组设置 indexArr list2 list3 的值
		if (indexArr.value.length == 3) {
			console.log("三层数据");
			if (index1 != indexArr.value[0]) {
				console.log('第一列变化,更新 2 3');
				setIndexArr([index1, 0, 0])
				list2.value = list.value[index1].children
				list3.value = list.value[index1].children[0].children
			} else if (index2 != indexArr.value[1]) {
				console.log('第二列变化,更新 3');
				setIndexArr([index1, index2, 0])
				list3.value = list.value[index1].children[index2].children
			} else if (index3 != indexArr.value[2]) {
				console.log('第三列变化,更新 3');
				setIndexArr([index1, index2, index3])
			}
		} else if (indexArr.value.length == 2) {
			console.log('两层数据');
			if (index1 != indexArr.value[0]) {
				console.log('第一列变化,更新 2');
				setIndexArr([index1, 0])
				list2.value = list.value[index1].children
			} else if (index2 != indexArr.value[1]) {
				console.log('第二列变化,更新 2');
				setIndexArr([index1, index2])
			}
		} else {
			console.log('一层数据');
			setIndexArr([index1])
		}
	}
	const showPopup = (arr) => {
		//样式
		if (props.isTab) uni.hideTabBar()
		popup.value.open('bottom')
		//设置indexArr list2 list3
		if (arr.length == 0) {
			console.log('无初始值,根据list设置初始indexArr', );
			if (list.value[0].children != undefined) {
				console.log('初始两层');
				setIndexArr([0, 0])
				list2.value = list.value[0].children
				if (list.value[0].children[0].children != undefined) {
					console.log('初始三层');
					setIndexArr([0, 0, 0])
					list3.value = list.value[0].children[0].children
				}
			} else {
				console.log('初始一层');
				setIndexArr([0])
			}
		} else {
			console.log('有初始值,直接赋给indexArr', arr);
			setIndexArr(arr)
			if (list.value[0].children != undefined) {
				console.log('有第一层,更新第二层');
				list2.value = list.value[arr[0]].children
				if (list.value[0].children[0].children != undefined) {
					console.log('有第二层,更新第三层');
					list3.value = list.value[arr[0]].children[arr[1]].children
				}
			}
		}
	}
	const closePopup = (isSave) => {
		if (isSave) {
			emit('setIndexList', indexArr.value)
		}
		if (props.isTab) uni.showTabBar()
		popup.value.close('bottom')
	}
	const setIndexArr = (arr) => {
		indexArr.value = arr
	}
	const popupChange = (e) => {
		if (e.show === false && props.isTab) uni.showTabBar()
	}
	defineExpose({=
		showPopup,
		closePopup,
	})
</script>


<style lang="scss" scoped>
	.myPickerBox {
		box-sizing: border-box;
		width: 750rpx;
		height: 690rpx;
		background: #F5F5F5;
		border-radius: 24rpx 24rpx 0rpx 0rpx;
		padding: 32rpx 40rpx 0;

		.uni-padding-wrap {
			height: 48rpx;
			padding-bottom: 32rpx;
			display: flex;
			justify-content: space-between;
			align-items: center;

			.left {
				width: 64rpx;
				height: 48rpx;
				font-family: PingFang SC, PingFang SC;
				font-weight: 400;
				font-size: 32rpx;
				color: rgba(0, 0, 0, 0.45);
				line-height: 48rpx;
				text-align: center;
			}

			.center {
				display: flex;
				justify-content: space-between;
				align-items: center;

				.center_tital {
					width: 128rpx;
					height: 48rpx;
					font-family: PingFang SC, PingFang SC;
					font-weight: 500;
					font-size: 32rpx;
					color: rgba(0, 0, 0, 0.95);
					line-height: 48rpx;
					text-align: center;
					margin: 0 16rpx;
				}

				.center_img {
					display: block;
					width: 12rpx;
					height: 12rpx;
				}
			}

			.right {
				width: 64rpx;
				height: 48rpx;
				font-family: PingFang SC, PingFang SC;
				font-weight: 500;
				font-size: 32rpx;
				color: #FF7611;
				line-height: 48rpx;
				text-align: center;
			}
		}

		.box_hide {
			height: 488rpx;
			border-radius: 24rpx 24rpx 24rpx 24rpx;
			overflow: hidden;

			.pickerView {
				box-sizing: border-box;
				width: 670rpx;
				height: 488rpx;
				background: #FFFFFF;
			}

		}
	}

	.item {
		line-height: 75rpx;
		text-align: center;
	}
</style>

父组件调用:传入setIndexList方法设置下标数组,传入数组[{value,label,childre}]、setAddress获取下标数组,渲染数组最多三层

	<myPicker :list="addressList" @setIndexList="setAddress" ref="myPicker" :tital="'选择城市'"> 
	</myPicker>
        <script setup>
            const addressList = [{
					value: "111",
					label: "111",
					children: [{
							value: "111-111",
							label: "111-111",
							children: [{
								value: "111-111-111",
								label: "111-111-111",
							}, {
								value: "111-111-222",
								label: "111-111-222",
							}]
						},
						{
							value: "111-222",
							label: "111-222",
							children: [{
								value: "111-222-111",
								label: "111-222-111",
							}, {
								value: "111-222-222",
								label: "111-222-222",
							}]
						},

					]
				},
				{
					value: "222",
					label: "222",
					children: [{
							value: "222-111",
							label: "222-111",
							children: [{
								value: "222-111-111",
								label: "222-111-111",
							}]
						},
						{
							value: "222-222",
							label: "222-222",
							children: [{
									value: "222-222-111",
									label: "222-222-111",
								},
								{
									value: "222-222-222",
									label: "222-222-222",
								}
							]
						}
					]
				}
			]
        </script>