uniapp实现picker三级数据连选弹框组件,支持省市区,支持异步props数据,拿去改吧改吧样式就能直接用
(vue3组合式api,使用uni-popup嵌套picker-view实现,传入)
效果展示:
代码:每种情况都判断了
<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>