文章来源于网络收集而来,版权归原创者所有,如有侵权请及时联系!
橡皮筋问题
IOS 上,当页面滚动到顶部或底部仍可向下或向上拖拽,并伴随一个弹性的效果。该效果被称为“rubber band”——橡皮筋。
IOS 和安卓不同,即使页面没有设置滚动,仍然可以拉扯,给人一种橡皮筋的感觉,可以看到下面的效果。
那么,怎么解决这个问题呢?
overflow 给定宽高
html, body {
width: 100%;
height: 100%;
overflow: hidden;
}
禁用 touchmove 事件
document.body.addEventListener('touchmove', function (e) {
e.preventDefault()
}, {passive: false})
监听滚动禁止
IOS 橡皮筋的原理还是通过滚动,只不过与安卓不同的是,当到边界状态时,仍允许滚动,如果替 IOS 禁用边界的情况,理论上就可以实现对橡皮筋效果的禁用。
import { useEffect } from 'react';
export const useForbidIosScroll = (): void => {
let startEvent: TouchEvent;
const cancelEvent = (e: TouchEvent): void => {
// 有个瑕疵就是,如果是大惯性的那种滚动,浏览器该事件并不接受你禁用当前正在执行的动作
// 导致如果猛地滑动会出页面边界
if (e.cancelable) {
e.preventDefault();
}
};
const checkScroll = (e: TouchEvent): void => {
const startY = Number(startEvent?.touches[0].pageY);
const endY = Number(e?.touches[0].pageY);
// 下滑且滑动到底
if (startY > endY && window.scrollY + window.innerHeight >= document.body.scrollHeight) {
cancelEvent(e);
}
// 上滑且滑动到顶
if (startY < endY && window.scrollY <= 0) {
cancelEvent(e);
}
};
useEffect(() => {
const start = (e: TouchEvent): void => {
startEvent = e;
};
const end = (e: TouchEvent): void => {
checkScroll(e);
};
window.addEventListener('touchstart', start);
window.addEventListener('touchmove', end, { passive: false });
return (): void => {
window.removeEventListener('touchstart', start);
window.removeEventListener('touchmove', end);
};
}, []);
};
这个效果其实并不是很理想,即使脚本已经走到中断的逻辑,滚动的行为在到达边界的时候仍然不会中止。
到谷歌浏览器开发者文档里可以查看到,浏览器的事件其实分为两种,cancelable(可暂停)和 uncancelable(不可暂停),能够通过阻止默认事件的和阻止冒泡的都是可暂停的事件,滚动事件和鼠标滚轮事件,在触发的瞬间,就已经决定了要滚动到终点再停止,你只能暂停可能会影响滚动的前提的导线事件,这个场景下,滚动事件就已经是起源的操作,不存在间接触发,所以不行。
简单方案(推荐)
有一个很简单的方案,并且可以完美解决,给 body 进行隐藏,然后对根节点设置 100 页宽的高度,将外部 body 的滚动移动到页面内,这样外界的滚动相关的问题都会解决,因为页面采用的实际是内部滚动。
styles/globals.css
.forbidScroll {
height: 100vh;
overflow: hidden;
}
body {
overflow: hidden;
}
#__next {
height: 100vh;
overflow: auto;
}
看看改后的效果,发现橡皮筋的功能已经禁用了,因为现在页面采用的是页面内部 div 的滚动,外部 body 的滚动相关的问题也随之解决。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论