在 uni-app 中实现饿了么式联动效果需用 scroll-view 监听 detail.scrolltop,配合 $nexttick 缓存各分类 offsettop,通过节流遍历匹配当前索引,协同左侧高亮与右侧 js 吸顶,并三重校验首次渲染高度。

饿了么商家详情页那种“左菜单固定 + 右内容滚动联动 + 吸顶标题”的效果,在 uni-app 里不是靠一个组件就能搞定的,得靠 scroll-view + 元素高度计算 + @scroll 事件监听 + 动态 class 控制,核心是「滚动位置映射到菜单索引」。
怎么用 scroll-view 获取实时滚动位置
右侧面板必须用 scroll-view 包裹,且必须设 scroll-y 和固定高度(不能用 100vh,小程序不认),否则 @scroll 不触发或值不准:
-
scroll-view的height要显式写死,比如calc(100vh - 200rpx),并配合overflow: hidden防止双滚动条 -
@scroll回调里拿到的是detail.scrollTop,这是当前滚动偏移量(单位 rpx),不是百分比 - 别用
scroll-into-view自动跳转——它会打断用户手势,导致左右不同步
如何计算当前滚动到哪个菜品分类
关键不是监听“滚动结束”,而是每帧判断 scrollTop 落在哪个分类区块内。需要提前缓存每个分类标题的 offsetTop(注意:必须在 mounted 后、$nextTick 里获取,否则 DOM 还没渲染):
- 用
uni.createSelectorQuery()查每个.cate-title的位置,存进数组this.titleOffsets = [0, 120, 280, ...] - 滚动时遍历这个数组,找到最后一个 ≤
scrollTop + stickyTop的索引(stickyTop是吸顶预留高度) - 不要用
Math.floor(scrollTop / itemHeight)算——菜品项高度不统一,标题高度也不同,硬除必错
左侧菜单高亮和右侧标题吸顶怎么协同
吸顶和高亮是两个独立逻辑,但依赖同一个 currentIndex:
- 左侧菜单用
:class="{ 'active': currentIndex === index }"控制样式,别用v-for里直接写index === currentIndex,性能差 - 右侧每个分类标题加
position: sticky+top: statusbarHeight + navHeight,但 iOS 小程序不支持 sticky,必须降级为 JS 控制transform: translateY()或top定位 - 吸顶临界点要减去导航栏高度(
uni.getSystemInfoSync().statusBarHeight+ 自定义导航高度),否则会卡在状态栏下面
为什么滚动卡顿或联动延迟
常见性能坑都在 DOM 查询和计算上:
- 每次
@scroll都调createSelectorQuery?绝对不行,查一次缓存好 - 没节流
@scroll:iOS 微信小程序每秒触发上百次,直接用throttle包一层,30ms 间隔足够流畅 - 用
v-if控制整个分类区块显隐?会导致 DOM 频繁销毁重建,改用v-show或 CSSopacity: 0; height: 0; - 如果用了
uview或uni-ui的组件,确认它们没内部强制重绘——某些封装 scroll-view 会额外加 wrapper 层,影响 offsetTop 计算
真实项目里最易被忽略的,是「首次渲染时 titleOffsets 拿不到准确值」——因为图片、字体加载未完成,高度会变。得监听 onReady + $nextTick + 图片加载完成事件(@load)三重保险,再执行 offset 缓存。











