scroll-view 到底部需用 bindscroll 监听 scrollTop + windowHeight ≈ scrollHeight(容差2px),禁用不可靠的 scrollHeight,用 boundingClientRect 获取真实高度,并加防抖和 loading 状态守卫。
scroll-view 的 bindscroll 事件怎么监听到底部
uni-app 的 scroll-view 不像原生 web 那样能直接读 scrolltop 和 scrollheight,它只通过 bindscroll 抛出一个 detail 对象,里面只有 scrolltop(垂直滚动距离)、scrollleft(水平)、scrollheight(整个内容高度)和 scrollwidth —— 但注意:scrollheight 在某些平台(尤其是微信小程序)里**不可靠或恒为 0**。
所以判断是否到底部,得靠 scrollTop + windowHeight ≈ scrollHeight 这个逻辑,但必须加容差,不能用严格相等:
-
scrollHeight和scrollTop是整数,但计算过程可能有小数误差,建议用Math.abs(a - b) 判断 - 微信小程序中
scrollHeight可能未及时更新,尤其首次渲染或动态加载后,要等$nextTick或延时再取 - H5 平台相对准确,但也要注意 CSS 盒模型影响(比如 padding、border 导致实际可滚动区域偏差)
为什么 scroll-view 的 scroll-into-view 不影响到底部判断
scroll-into-view 是主动滚动到某个子元素,它会触发 bindscroll,但不会改变你判断“是否自然滚动到底”的逻辑。很多人误以为用了它就等于“已到底”,其实不是——它只是把视图拉过去,scrollTop 值变了,但你仍需自己算是否真贴底。
-
scroll-into-view的目标元素必须有唯一id,且该id不能含特殊字符(如点、空格),否则在小程序里失效 - 如果目标元素高度 > viewport 高度,
scroll-into-view可能只滚到顶部,而非真正“底部”位置 - 它不提供回调,无法知道滚动何时结束,所以不能依赖它来触发“到底加载”逻辑
uni-app 中 onReachBottom 和 scroll-view 到底部的区别
onReachBottom 是页面级生命周期,只对 page 生效,监听的是整个页面滚动到底(基于 page 的 scrollY),跟 scroll-view 完全无关。如果你在页面里嵌了 scroll-view,它的滚动不会触发 onReachBottom。
- 想实现局部区域下拉加载,必须用
scroll-view的bindscroll+ 手动计算 - 混用两者容易造成重复请求:比如同时监听
onReachBottom和scroll-view底部,结果同一份数据被拉两次 - App 端
onReachBottom触发时机比 H5 更敏感,有时轻微滚动就触发,而scroll-view更可控
实际可用的到底部判断代码片段(带容差 & 兼容处理)
下面这段逻辑在 H5、微信小程序、App 三端都验证过,关键点是:先确保 scrollHeight 有效,再做差值比较,且避免高频触发:
onScroll(e) {
const { scrollTop, scrollHeight } = e.detail
const query = uni.createSelectorQuery().in(this)
query.select('#my-scroll').boundingClientRect()
query.exec(res => {
if (!res || !res[0]) return
const windowHeight = res[0].height
// 容差设为 2px,防止四舍五入误差
if (scrollHeight > 0 && Math.abs(scrollTop + windowHeight - scrollHeight) < 2) {
this.loadMore()
}
})
}- 不用
uni.getSystemInfo取窗口高度,因为那是整个屏幕高,不是scroll-view自身高 - 必须用
boundingClientRect()获取当前scroll-view实际渲染高度,否则在 flex 布局里容易算错 - 加防抖(比如用
clearTimeout+setTimeout包一层)比节流更稳妥,因为到底部通常只希望触发一次
最常被忽略的是:动态插入内容后没重置判断状态,比如加载新数据 append 到列表末尾,但没清掉上次的 “已到底” 标记,导致后续滚动不再触发 —— 记得在 loadMore 开始时设个 loading = true,结束再设 false,并在 onScroll 里加守卫条件。










