唯一稳定方案是scroll-view(垂直)+ swiper(水平)组合:左侧用scroll-view固定分类导航,右侧用swiper切换内容区,通过current和scroll-into-view联动实现跨端稳定。

scroll-view + swiper 组合是唯一稳定方案
直接用 scroll-view 做横向筛选栏,在 iOS 上滑动卡顿、安卓点击失灵、小程序里还可能和下拉刷新冲突——这不是你代码问题,是组件定位机制不匹配。商品筛选栏本质是「离散选项」,不是连续滚动容器,硬套 scroll-view 的 scroll-x 会放大平台差异。真正能跨端稳定的,是左侧用 scroll-view(scroll-y="true") 固定分类导航,右侧用 swiper(vertical="false") 控制内容区切换,靠 current 和 scroll-into-view 联动。
吸顶筛选栏必须手动监听滚动,不能依赖 position: sticky
position: sticky 在微信/支付宝/百度小程序里完全不生效,H5 端也要求父容器有明确高度且不能设 overflow: hidden,实际项目中基本等于不可用。正确做法是:把筛选栏(比如分类导航条)包裹在普通 view 中,用 scroll-view 包裹整个内容区,监听其 bindscroll 事件,读取 detail.scrollTop,与筛选栏原始 offsetTop 比较,动态设置 isSticky 数据字段,再通过 class 切换 position: fixed 状态。
- 务必在
onReady或$nextTick后获取offsetTop,否则可能为 0 - fixed 元素会脱离文档流,必须在原位置放一个等高占位
view,否则页面会“抖一下” - 节流不能省:
requestAnimationFrame或 16ms 间隔,避免低端机 setData 频繁触发卡顿
左右滑动切换内容区时,如何保持筛选栏吸顶不跳动
常见错误是把筛选栏也放进 swiper,结果一滑动就跟着动,或者吸顶后位置错乱。筛选栏必须独立于内容区 swiper 实例之外,只响应滚动,不参与内容切换。内容区用 v-if 或 visibility: hidden 控制显示,而不是塞进同一个 swiper;每个内容栏用单独的 scroll-view,并在离开前存 scrollTop,进入时用 scroll-top 还原(注意要在 $nextTick 后执行)。
- 筛选栏的吸顶状态判断逻辑,只依赖主
scroll-view的scrollTop,和当前current值无关 - swiper 的
@change事件只用来同步左侧高亮和更新当前内容索引,不触发吸顶状态重算 - 如果需要“滑动内容区自动高亮对应筛选项”,得额外监听
scroll-view的滚动距离,计算当前可视区域落在哪个分类区块内,再更新current
容易被忽略的细节:吸顶高度偏移与多端一致性
吸顶后,下方内容会向上顶,导致锚点跳转偏移、滚动位置错乱。最常被忽略的是:吸顶栏高度必须和占位 view 高度严格一致,且这个值不能写死在 JS 里。应该用 uni.createSelectorQuery() 在 onReady 中实测获取,或在 CSS 里用 var(--tab-height) 统一管理。iOS 微信小程序中,状态栏高度 + 导航栏高度 + 筛选栏自身高度,三者叠加后若没对齐,吸顶就会“悬空”或“压住内容”。
另外,scroll-into-view 跳转到某个分类区块时,要减去吸顶栏实际高度(比如 offsetTop - 88),否则目标区块会被遮挡——这个 88 不是 magic number,是你用 getBoundingClientRect 测出来的真值。


















