使用getBoundingClientRect 针对scrollTop一直为0且documentElement无效的解决方案

使用getBoundingClientRect 针对scrollTop一直为0且documentElement无效的解决方案

💡 原文中文,约1600字,阅读约需4分钟。
📝

内容提要

作者修复了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 兜底,其他业务代码完全无需改动,测试通过。

🏷️

标签

➡️

继续阅读