scroll-view 横向滚动+吸顶必须外置 Tab 栏、设固定高度、监听 bindscroll;Tab 需唯一 id 配 scroll-into-view 实现居中,内容区联动高亮须基于节点位置计算临界值。

scroll-view 嵌套结构必须这么写
横向滚动 + 吸顶不能靠两个独立组件拼凑,必须用 scroll-view 包裹内容区,吸顶 Tab 单独置于其外层,否则 iOS 小程序里会失效。常见错误是把 Tab 也塞进同一个 scroll-view 里——结果要么吸顶不生效,要么横向滚动卡顿掉帧。
- Tab 栏必须脱离
scroll-view的滚动流,用position: fixed或动态 class 控制显隐 -
scroll-view需设固定高度(如height: calc(100vh - 100rpx)),否则bindscroll不触发 - Tab 容器自身也要设
width: 100%和white-space: nowrap,子项用display: inline-block或flex-shrink: 0 - 真机调试时关掉 HBuilderX 的「启用滚动区域优化」,尤其 iOS 下这个开关会让
scroll-view被内核拦截
吸顶逻辑必须监听 scroll-view 的 bindscroll
别用 onPageScroll,页面级滚动在小程序里无法精确捕获 Tab 区域的滚动偏移,且和下拉刷新冲突。所有吸顶判断、高亮切换、滚动定位都得从 scroll-view 的 @scroll 事件里取 detail.scrollTop。
-
offsetTop必须在onReady或nextTick后获取,onMounted里直接取 DOM 高度大概率是 0 - 吸顶阈值建议设为
statusBarHeight + navBarHeight(iOS 通常 88rpx,Android 一般 100rpx),硬写100会遮状态栏 - 吸顶后内容上跳?加一个占位
<view :style="{ height: isSticky ? '88rpx' : '0' }"></view>,别用padding-top,它会影响scroll-view内容起始位置
Tab 居中滚动必须用 scroll-into-view,不是 scroll-left
手动算 offsetLeft 再设 scroll-left 是最常见翻车点:不同平台返回值不一致,还漏算 padding/margin,iOS 上经常滚偏半个 Tab。uni-app 官方推荐且多端兼容的只有 scroll-into-view。
- 每个 Tab 项必须带唯一
id(如tab-0、tab-1),绑定到scroll-view的:scroll-into-view="currentId" - 点击 Tab 后立即更新
currentId,框架会自动平滑滚动并居中,无需节流 - 不要在
scroll-into-view触发的同时改current变量再触发高亮——这两件事必须解耦,否则某些机型渲染错乱 - Tab 文字长度差异大?统一设
min-width: 120rpx+text-align: center,避免居中计算失准
联动高亮要靠内容区块位置映射,不是单纯 scroll-y
用户滑动内容区时自动高亮对应 Tab,这需要把内容区块的 boundingClientRect 和当前 scrollTop 做比对。直接监听 scroll-y 数值做区间判断容易误判,尤其在快速滚动或惯性滑动时。
- 用
uni.createSelectorQuery().in(this)批量查所有内容区块节点,exec()只调一次 - 每个区块的临界位置 =
top - totalOffset(totalOffset= 状态栏 + 导航栏高度),不是原始top - 高亮判断用
scrollTop >= sectionTop && scrollTop ,别用 <code>==或===,滚动是连续值 - 防抖用
requestAnimationFrame,不用setTimeout,否则快速滚动时高亮滞后半拍
吸顶和横向滚动本身都不难,难的是它们叠加时 DOM 层级、滚动上下文、跨端渲染差异三者咬合的那一小段间隙——那里藏着最多 runtime 错误,而且只在真机上爆发。


















