uni-data-picker要求data严格树形且children必须为数组(不可null或别名),异步加载需防重与响应校验,自定义UI须改用picker-view,H5下multiSelector不联动,必须统一用picker-view实现。

uni-data-picker 的 data 格式必须严格树形,children 不能为空数组
很多自定义风格失败,其实根本没走到样式环节——数据结构先报错了。uni-data-picker 不认 subs、nodes 或 children: null,只认 children 字段且必须是数组(哪怕为空)。后端返回的 children: null 必须在前端转成 children: [],否则组件直接中断渲染。
常见错误现象:选择第一级后第二级空白,控制台无报错但 bindchange 不触发;或某一级展开后整个 picker 消失。
- 正确写法:
{ value: 'zj', label: '浙江', children: [{ value: 'hz', label: '杭州' }] } - 错误写法:
{ id: 'zj', name: '浙江', subs: [...] }(字段名不匹配) - 错误写法:
{ value: 'zj', label: '浙江', children: null }(类型错误)
异步加载必须手动防重 + 响应校验,不能只靠 resolve
uni-data-picker 的 lazy-load 函数只是个回调入口,它不帮你管并发、不拦截乱序响应、也不自动设 loading。用户连点两下“江苏”,可能触发两次请求,而第二次请求若先返回,就会把“浙江”的城市列表塞进“江苏”节点下。
关键做法是在发起请求前生成唯一标识,并在校验响应时比对:
- 在
data中声明requestId: 0 - 在
lazy-load里:this.requestId = Date.now(); this.$http.get('/api/areas', { params: { pid: node.value } }).then(res => { if (res.data.id !== this.requestId) return; resolve(res.data.list); }) - loading 状态要显式绑定到
loadingprop,例如::loading="loadingMap[node.value]"
自定义 UI 只能用 picker-view,uni-data-picker 不支持 slot 替换内部结构
想改字体、加图标、调整列宽?别在 uni-data-picker 上折腾。它的 slot 只作用于“确认/取消按钮”,无法覆盖滚动列本身。真要自定义样式,唯一可靠路径是弃用封装组件,直接用原生 picker-view + 手动逻辑。
此时需注意三件事:
-
value数组长度必须等于列数,缺一不可;第二列切换后,第三列value必须立刻重置为0,否则越界显示空白 - 所有
range必须是纯字符串数组,不能传对象;range-key在 H5 下无效,别依赖它 - iOS 微信中
bindchange触发太频繁,必须加setTimeout(() => {...}, 100)防抖,否则滚动未停就 setData 会导致卡顿
H5 平台 mode="multiSelector" 完全不联动,必须切回 picker-view
这是最常被忽略的跨平台陷阱。H5 下 <picker mode="multiSelector"> 渲染出来就是三列独立滚动器,选了“广东”不会自动刷新第二列的市列表。官方文档没明说,但实测所有 uni-app 版本均如此。
解决方案只有一个:H5 和小程序共用同一套 picker-view 实现。虽然开发量稍大,但避免了条件编译和双端行为不一致的风险。
复杂点在于:每列 range 更新后,不仅要重置后续列的 value,还要确保 picker-view 的 columnchange 事件能准确识别当前操作的是第几列——建议用 event.detail.column 判断,而不是靠闭包变量存状态。


















