内容提要
作者修复了iPhone X内置WebView中滚动加载误触发下拉刷新的问题:该设备获取scrollTop始终为0,于是改用getBoundingClientRect().top取负值作为scrollTop的兜底方案,兼容性好,业务代码无需改动,测试通过。
延伸解读
问题定位:特定 WebView 的 scrollTop 异常
文章指出,在 iPhone X 的内置 WebView 中,常规的 document.documentElement.scrollTop 和 document.body.scrollTop 始终返回 0,导致滚动加载和下拉刷新逻辑误判。作者通过 vConsole 打印确认该设备上 scrollTop 无法获取,而其他设备正常。这提醒开发者,在混合开发环境中,不能完全依赖 scrollTop 的通用获取方式,需考虑特定 WebView 的兼容性差异。
兜底方案:利用 getBoundingClientRect 计算滚动距离
作者采用 getBoundingClientRect().top 的负值作为 scrollTop 的兜底值,即 -document.querySelector('.container').getBoundingClientRect().top。该 API 兼容性极好,从 IE5 时代就已存在,且能准确反映元素相对视口的位置。方案仅需在原有 scrollTop 定义后追加该表达式,业务代码无需改动,即可在异常设备上获取正确的滚动距离。
实施注意:选择正确的监听元素
文章强调,getBoundingClientRect 需绑定到实际滚动的容器元素上,可以是 body 或其他业务容器。开发者应根据页面结构选择正确的元素,否则计算出的 top 值可能不准确。此外,作者提到 y 属性兼容性不佳,因此选用 top 属性更稳妥。该方案虽简单有效,但需确保容器元素在滚动过程中位置变化能被正确捕获。
Q&A
iPhone X 内置 WebView 中 scrollTop 一直为 0 导致滚动加载误触发下拉刷新,怎么解决?
在获取 scrollTop 的代码中增加兜底方案:使用 getBoundingClientRect().top 的负值作为 scrollTop。例如:const SCROLL_TOP = document.documentElement.scrollTop || document.body.scrollTop || -document.querySelector('.container').getBoundingClientRect().top。这样无需修改其他业务代码即可修复问题。
为什么在 iPhone X 的内置 WebView 中 document.documentElement.scrollTop 和 document.body.scrollTop 都获取不到滚动距离?
文章指出在该特定设备的内置 WebView 中,document.documentElement.scrollTop 和 document.body.scrollTop 始终返回 0,导致无法获取真实滚动距离。具体原因文章未深入分析,但确认是环境兼容性问题。
getBoundingClientRect().top 如何用来替代 scrollTop?
getBoundingClientRect() 返回元素相对于视口的位置信息,其中 top 表示元素顶部距离视口顶部的距离。当页面滚动时,该值会变为负数,其绝对值即为页面滚动的距离。因此可以用 -element.getBoundingClientRect().top 来模拟 scrollTop。
使用 getBoundingClientRect 获取 scrollTop 的兼容性如何?
文章提到 getBoundingClientRect 是从 IE5 时代就存在的 API,兼容性非常好。但需要注意,其 y 属性的兼容性较差,因此推荐使用 top 属性来获取数据。
除了 document.documentElement 和 document.body,还有哪些元素可以用 getBoundingClientRect 来获取滚动距离?
文章建议根据实际业务需求选择具体的元素,可以是 body,也可以是其他容器元素(如 .container)。只要对该元素调用 getBoundingClientRect().top 并取负值即可。
这个解决方案需要修改其他业务代码吗?
不需要。该方案仅修改 scrollTop 的定义,增加 getBoundingClientRect 兜底,其他业务代码完全无需改动,测试通过。