三级联动筛选需省、市用uni-data-select,区级改用uni-data-checkbox或radio-group;吸顶导航与筛选栏分离布局;scroll-view内请求须防抖+requestId校验;多端兼容需差异化处理。

uni-data-select 两级联动 + 手动控制第三级
uni-data-select 本身不支持三级联动,连两级都要靠手动通信实现。想做“省→市→区”三级筛选,前两级用 uni-data-select 是可行的,但第三级必须换方案——它无法动态禁用某一项(比如“该市无区”时灰显),也不能多选,强行嵌套会导致交互断裂、数据残留。
实际做法是:
- 省、市两个
uni-data-select组件各自绑定独立v-model,比如provinceCode和cityCode - 监听省的
@change,清空市和区的值,重置市的options;再监听市的@change,清空区的值,并触发接口或查映射表获取区列表 - 区级不用
uni-data-select,改用uni-data-checkbox或scroll-view+radio-group渲染,传入动态生成的options数组 - 注意初始状态:区级组件默认
disabled或隐藏,等cityCode有值后再显示并加载数据
吸顶导航栏与筛选栏分离布局
别把筛选栏直接塞进吸顶导航里。吸顶区域要轻量、固定高度、不随内容滚动重绘;而三级筛选涉及下拉展开、异步加载、选项刷新,放进去容易触发重排、iOS 上 z-index 错乱、甚至 touch 穿透。
正确结构是:
- 顶部用
position: sticky或fixed实现吸顶导航(如分类 tab) - 筛选栏作为独立区块,放在导航下方、内容上方,用
scroll-view包裹整个可滚动区域,监听其@scroll事件判断是否到达吸顶临界点 - 当滚动距离超过导航栏高度时,给筛选栏加
position: fixed和对应 top 值,同时设置z-index高于内容但低于导航 - H5 端慎用
position: sticky,部分安卓 WebView 不支持,优先走 JS 控制 fixed
scroll-view 内部联动与防抖请求
在 scroll-view 里做三级筛选,最大的坑是输入搜索触发的请求乱序和重复。用户快速输入“北京朝阳”,可能发三四个请求,后发先回,导致区列表错乱或清空失效。
关键控制点:
- 所有搜索请求必须加防抖:
clearTimeout(this.searchTimer)+this.searchTimer = setTimeout(..., 300) - 每次请求带唯一标识
requestId,响应回来先比对response.id === this.requestId,不匹配就丢弃 - 输入框获得焦点时,禁用其他筛选控件(如省/市下拉),避免用户一边输一边点,状态冲突
- 小程序平台尤其注意:
watch监听深层字段(如form.city)必须加deep: true,否则变更不触发;更推荐用computed生成依赖链,比如areaOptions直接依赖cityCode
多端兼容性细节不能跳过
同一套逻辑在 App、小程序、H5 表现差异极大,不是写一次就能跑通:
- H5 端
uni-data-select会退化为原生<select>,样式不可控,且无法监听滚动中变化,别试图加高亮或实时过滤 - 微信小程序里,
scroll-view的@scroll在 iOS 上可能延迟 1~2 帧,吸顶计算要用scrollTop而非event.detail.scrollTop(后者不准) - App 端
picker支持mode="multiSelector",但 H5 必须用mode="selector"+range-key,否则三级数据结构解析失败 - 所有接口请求加时间戳参数
?t=<code>Date.now(),绕过安卓 WebView 的 GET 缓存
三级联动筛选真正难的不是写代码,而是让每一级的状态变更都可预测、可中断、可回滚。尤其是区级多选后,用户切到别的市再切回来,旧选中项要不要保留?这个逻辑必须在 cityCode change 时显式处理,而不是依赖组件自动同步。


















