ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

wheel 滚轮事件 ---兼容触摸板

2021-05-14 23:00:47  阅读:333  来源: 互联网

标签:wheel current 触摸板 滚动 防抖 --- 事件


wheel 滚轮事件

一、事件说明

当滚动鼠标滚轮或操作其它类似输入设备时会触发滚轮事件

Tips:

  • 使用触摸板触发该事件,由于系统的平滑处理,会触发多次该事件
  • IE 下无法使用触摸板触发该事件
  • 替换了已被弃用的非标准 mousewheel 和 DOMMousewheel 事件。

二、兼容性

桌面端
浏览器版本
Chrome61
Edge12
Firefox17
IE9
Opera48
Safari7
移动端
浏览器版本
WebView Android61
Chrome Android61
Firefox for Android17
Opera Android45
Safari on iOS7
Samsung Internet8

三、常规用法(不考虑触摸板的情况)

// wheel事件回调
const onWheel = useCallback(
  e => {
    console.log(e)
  },
  []
);

useEffect(() => {
  window.addEventListener('wheel', onWheel);

  return function () {
    window.removeEventListener('wheel', onWheel);
  };
}, []);

四、加上防抖

上面的做法虽然可以实现功能,但是每滚动一下就会处理一次逻辑,很浪费性能而且在IE上面还会导致滚动卡顿不流畅,这个时候就可以加上防抖的效果再尝试一下。

const { current} = useRef({
  isScroll: true, // 是否可以滚动
  timer: null, // setTimeout句柄
  delay: 300 // 防抖时间
})
// wheel事件回调
const onWheel = useCallback(
  e => {
    // 是否可以滚动,不写到setTimeout里面就可以先执行逻辑,在进行防抖,避免造成不跟手的情况
    if (current.isScroll) {
      current.isScroll = false;
      ...
    }
    // 如果已经上次的防抖效果还没有释放,又触发了wheel回调,那么就取消上次的防抖效果
    if (current.timer) {
      clearTimeout(current.timer);
    }
    // 重新开始计算
    current.timer = setTimeout(() => {
      current.isScroll = true;
    }, current.delay);
  },
  []
);

useEffect(() => {
  window.addEventListener('wheel', onWheel);

  return function () {
    window.removeEventListener('wheel', onWheel);
  };
}, []);

五、考虑触摸板的情况

上面的那种方法,已经可以解决大部分的情况,但是如果防抖的时间设置的少于一定时间,用上触摸板之后就会发现,轻轻的滑动一次,wheel事件的处理逻辑就会被触发好多次。


这种情况产生的原因,根据网上的说法是似乎系统为了实现平滑滚动的效果还是其他原因,当你手指离开触摸板后wheel依然还会执行一段时间。


解决办法

  1. 增加防抖的延迟时间。这个办法虽然可以解决触摸板滑动一次触发多次wheel事件的问题,但是可能会造成正常的滚动时页面根本滚不动的问题(即在防抖的时间内又触发了一次)
  2. 判断本次wheel事件是由系统的平滑处理所产生还是由正常的滚动所产生的,但是wheel事件的回调当中并没有提供可以区分这两种情况的属性,这个时候只能找一下正常滚动时的回调属性和由系统的平滑处理产生的回调属性这两者有什么不同了。


    根据对比可以发现,由系统的平滑处理所产生事件的移动距离基本都是小于100的,而且事件产生的时间间隔都很短,所以可以通过判断上次正常滚动的时间和本次事件产生的时间间隔还有本次事件的移动距离来判断,本次的事件是不是一次正常的滚动(并不是最优质的解决办法,还会有误判发生,但目前并没有想到更好的解决办法)。
// 获取时间戳(毫秒级别)
const getTime = useCallback(() => {
  return new Date().getTime();
}, []);

const { current } = useRef({
  isScroll: true, // 是否可以正常的滚动
  scrollTime: null, // 上次切换的时间戳(毫秒级别)
  timer: null, // setTimeout句柄
  interval: 500, // 两次滑动之间的最小事件间隔
  distance: 100, // 有效滑动的最小距离
  delay: 400, // 防抖时间
});

// wheel事件处理函数
const wheel = useCallback(
  e => {...},
  []
);

// wheel事件回调
const onWheel = useCallback(
  e => {
    const time = getTime();
    const y = e.deltaY; // 以垂直滚动为列

    if (current.scrollTime) {
      // 如果这次触发的时机跟上次切换的时机差大于一定时间,并且滑动距离大于一定距离,那么就认为是有效滑动
      if (
        time - current.scrollTime > current.interval &&
        Math.abs(y) >= current.distance
      ) {
        // 触摸板滚动
        wheel(e);
        clearTimeout(current.timer);
        current.isScroll = false;
        current.scrollTime = time;
      }
    }
    if (current.isScroll) {
      // 正常滚动
      wheel(e);
      current.scrollTime = getTime();
      current.isScroll = false;
    }
    if (current.timer) {
      clearTimeout(current.timer);
    }
    current.timer = setTimeout(() => {
      current.isScroll = true;
    }, current.delay);
  },
  []
);

useEffect(() => {
  window.addEventListener('wheel', onWheel);

  return function () {
    window.removeEventListener('wheel', onWheel);
  };
}, []);

标签:wheel,current,触摸板,滚动,防抖,---,事件
来源: https://blog.csdn.net/hclle/article/details/116808813

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有