在苹果的WKWebview中存在两个弹性滚动,分别是全局和局部滚动回弹,全局回弹最方便的办法是让客户端同学设置webview属性,禁用回弹效果,这样无需前端做兼容处理,也很方便实用,不过即便是客户端禁用了回弹,局部滚动中的回弹依然会存在。

Q: 为什么需要关注这个回弹

如果局部滚动的区域大于 1/2 的屏幕高度,就会出现用户在局部滚动中连续滑动锁定在这个局部牢笼中,无法滚动到其他区域,让人产生页面滚到底部的感觉。

 

Q: 这个问题在哪些设备上会出现?

目前测试只有 iOS WKWebview 会出现 (UIWebview已经被淘汰了,不好测试就没测)。PC,Android 均无此问题

 

Q: 使用 -webkit-overflow-scrolling: touch 能不能解决这个问题?

答案,不能。在苹果的这次更新中提到,现在已经不需要设置该属性了。https://developer.apple.com/documentation/safari-release-notes/safari-13-release-notes

IOS滚动回弹效果和右滑返回 js ios弹性滚动_Math

在 iOS 13以上,已经无需设置该属性,而且上面的demo就是iOS14下的演示,我也单独设置了该属性发现行为表现确实一样。

解决方案

使用模拟滚动,而不是原生滚动,因为试了很多种方案原生滚动都无法实现滚动到边界自动穿透到全局滚动上,所以干脆彻底放弃原生滚动。

在 css 文件中禁用原生滚动

- overflow: auto;
+ overflow: hidden;

  

接着使用模拟滚动库,这里使用了 better-scroll 解决,下面几行代码

bs = new BScroll(listRef.current, {
                bounce: false,
                preventDefault: false,
                scrollY: true
            });

            bs.scroller.actionsHandler.hooks.on('move', ({ deltaX, deltaY, e }) => {
                if (Math.abs(bs.y) === 0 && deltaY > 0) {
                    // 向上滑动到边界, 允许顶层滚动
                    return;
                }
                if (Math.abs(bs.y) === Math.abs(bs.maxScrollY)) {
                    // 向下滑动到边界,允许顶层滚动
                    return;
                }
                e.preventDefault();
                e.stopPropagation();
            });

  

设置 preventDefault: false, 再在 move 中检测边界,如果不在边界上滚动,阻止冒泡和默认行为,此时仅在局部滚动,如果在边界上,则允许默认滚动处理,让上层处理滚动。


目前已知问题

  1. 由于betterscroll原理是使用transform进行移动,所以一些依赖视口检测的懒加载工具库可能会失效。