应放弃 uni-data-picker 改用弹层+列表组合实现可搜、可高亮、可联动的级联选择:通过 input 监听+防抖+异步请求获取扁平数据,用 scroll-view 渲染并手动控制层级与选中状态,配合转义正则标红关键字,同步更新多级字段。

直接用 uni-data-picker 会卡死或不联动?别硬扛
它默认只支持树形数据 + 原生样式,H5 端 mode="multiSelector" 根本不联动,iOS 滚动卡顿、搜索关键词后无法高亮、选中路径不能回填——这些不是 bug,是设计限制。真要自定义样式 + 搜索 + 高亮,必须放弃原生 picker,改用弹层 + 列表组合。
怎么搭一个可搜、可高亮、可联动的弹层级联列表
核心是三块:输入框监听 + 异步查数据 + 手动渲染层级列表。不是把数据塞进 range,而是自己控制每列展示内容和选中状态。
- 用
<input v-model="keyword">监听输入,加防抖(clearTimeout(this.timer)+setTimeout(..., 300)) - 每次输入触发
uni.request,传keyword给后端,返回匹配的省/市/区扁平数组(不是树形!),例如:[{id:"bj",name:"北京市"},{id:"sh",name:"上海市"}] - 拿到结果后,不塞进
picker,而是用<scroll-view></scroll-view>渲染列表,用v-for+indexOf+v-html或<span></span>包裹实现关键字标红 - 点击某项后,手动展开下一级(比如点“北京”,再请求
city?province=bj),同时清空后续层级已选值 - 注意:iOS 上
scroll-view里click可能失效,加cursor: pointer和z-index避免 touch 遮挡
watch 监听级联字段总不触发?别瞎配 deep
监听 form.province 却没反应,大概率是因为你没把它定义在 data() 返回对象里,或者用了 const 外部变量。更稳的方式是拆成平级字段:
- 定义为
provinceCode、cityCode、areaCode三个独立响应式字段 - 用
computed生成cityList:依赖provinceCode,自动请求或过滤本地数据 - 不要写
watch: { 'form.xxx'() {} },uni-app 小程序平台对嵌套超过两层的watch支持极差,容易丢变更
搜索结果里怎么标红关键字又不被 XSS 搞垮
别用 v-html 直接插字符串,尤其当 keyword 来自用户输入时。安全做法是先转义,再替换:
- 用正则
new RegExp(keyword.replace(/[.*+?^${}()|[]\]/g, '\$&'), 'gi')匹配,避免特殊字符崩掉正则 - 替换时用
<span style="color:red">${match}</span>,不是拼 HTML 字符串 - 如果后端返回的是已加工过的带标签文本(如
"北<em>京</em>"),前端就别再处理,直接v-html—— 但必须确保后端做了 XSS 过滤
最易被忽略的一点:搜索结果列表里点“北京市朝阳区”,得同步更新所有上级字段(provinceCode、cityCode),否则下次打开弹层还是显示旧路径;这个同步逻辑必须写在点击回调里,不能靠 watch 被动响应。











