返回介绍

橡皮筋问题

发布于 2024-09-11 01:01:38 字数 2758 浏览 0 评论 0 收藏 0

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文