在开发微信小程序时,地址选择功能是常见的业务需求。传统的解决方案往往存在几个痛点:一是数据量大导致加载缓慢,二是无法同时满足省市区三级和省市县街道四级的需求,三是港澳台地区的行政区划处理存在特殊性。基于这些痛点,我决定开发一个自封装的Uniapp地址级联选择器组件。
这个组件需要实现以下核心功能:
选择Uniapp+Vue3的组合主要基于以下考虑:
采用高德地图的行政区划API作为数据源,主要优势包括:
组件采用分层加载的设计思想:
javascript复制// 接口限流配置
const requestQueue = ref([])
const isRequesting = ref(false)
let lastRequestTime = 0
const REQUEST_INTERVAL = 350
// 接口请求限流处理
async function requestWithLimit(requestFn) {
return new Promise((resolve, reject) => {
requestQueue.value.push({
requestFn,
resolve,
reject
})
processRequestQueue()
})
}
这个机制确保了:
javascript复制// 选择省份
async function selectProvince(item) {
tempProvince.value = {...item}
tempCity.value = null
tempDistrict.value = null
tempStreet.value = null
cityList.value = []
districtList.value = []
streetList.value = []
noStreetRecord.value = {}
await loadCityData()
currentLevel.value = 1
}
关键设计点:
javascript复制watch(() => props.modelValue, async (val) => {
if (!val?.length) {
// 清空所有选择
return
}
const [p, c, d, s] = val
await loadProvince()
// 逐级匹配并加载数据
finalProvince.value = props.returnType === 'code' ?
provinceList.value.find(i => i.adcode === p + '') :
provinceList.value.find(i => i.name === p)
// 省略下级匹配代码...
}, {immediate: true, deep: true})
回显逻辑特点:
组件采用分级加载策略:
这种设计显著减少了初始数据加载量,提升了组件响应速度。
组件内部维护了多级缓存:
这种缓存机制避免了重复请求相同数据。
javascript复制const filtered = list.filter(item => !['台湾省', '香港特别行政区', '澳门特别行政区'].includes(item.name))
出于业务合规性和数据结构差异考虑,明确排除了港澳台地区。
javascript复制if (streetList.value.length === 0) {
noStreetRecord.value[districtAdcode] = true;
uni.showToast({
title: '该区县暂无街道数据,可直接确认',
icon: 'none'
})
}
对于没有街道数据的区县,组件会:
javascript复制const errorMessage = ref('加载失败 <view class="retry-btn" @tap="retryLoad">重试</view>')
async function retryLoad() {
loadError.value = false
// 根据当前层级重试对应数据加载
}
提供友好的错误提示和重试机制,增强用户体验。
html复制<view class="breadcrumb-item" :class="{
'is-active': currentLevel === 0,
'is-disabled': false
}" @tap="switchLevel(0)">
{{ tempProvince?.name || '省' }}
<up-icon name="arrow-right" size="14"
:color="currentLevel === 0 ? '#fff':'#999'"></up-icon>
</view>
面包屑导航特点:
css复制.selection-item {
height: 96rpx;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 24rpx;
background: #f7f7f7;
border-radius: 16rpx;
margin-bottom: 16rpx;
transition: all 0.2s ease;
border: 2rpx solid transparent;
&.is-selected {
background: #eaf4ff;
border-color: #1989fa;
color: #1989fa;
}
}
列表项设计要点:
html复制<RegionPicker v-model="value" />
| 参数名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| modelValue | Array | - | 绑定值,格式取决于returnType |
| returnType | String | 'name' | 输出类型:'name'或'code' |
| level | Number/String | 3 | 级联层级:3或4 |
| popupTitle | String | '选择地区' | 弹窗标题 |
| placeholder | String | '请选择地区' | 输入框占位符 |
| 事件名 | 说明 | 回调参数 |
|---|---|---|
| update:modelValue | 选择确认时触发 | 当前选择值数组 |
constant(safe-area-inset-bottom)处理底部安全区域enable-flex提升滚动性能这个组件在实际项目中已经稳定运行,处理了各种边界情况。通过合理的架构设计和性能优化,即使在低端设备上也能流畅运行。希望这个实现思路对大家有所启发,也欢迎提出改进建议。