事件处理程序被禁用的时间比预期的要长 [英] Eventhandler is disabled for longer than expected

查看:49
本文介绍了事件处理程序被禁用的时间比预期的要长的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在制作一个简单的完整视口滚动条.您可以通过触发 wheel 事件来更改部分.

为了防止事件处理程序在行中多次触发和跳过页面,我添加了一个计时器,计算存储在变量中的 date.now()date.now 之间的差异() 在 eventHandler 里面.这种情况主要发生在您滚动垃圾邮件时,它使您必须等待大约 3 秒才能再次滚动,而不是 200 毫秒.如何防止这种情况发生?

document.ready = (fn) =>{if (document.attachEvent ? document.readyState === "complete" : document.readyState !== "loading"){fn();} 别的 {document.addEventListener('DOMContentLoaded', fn);}}document.ready(() => {const SECTIONS = document.querySelectorAll('.section');让电流;让 onWheelTimeout = 'poop';让时间 = Date.now()//将第一部分初始化为活动的_.first(SECTIONS).classList.add('active');document.addEventListener('wheel', onWheel)函数 goSectionUp() {const current = document.querySelector('.active');current.classList.remove('active');如果(current.previousElementSibling){current.previousElementSibling.classList.add('active');} 别的 {_.last(SECTIONS).classList.add('active');}}函数 goSectionDown() {const current = document.querySelector('.active');current.classList.remove('active');如果(current.nextElementSibling){current.nextElementSibling.classList.add('active');} 别的 {_.first(SECTIONS).classList.add('active');}}功能在Wheel(e) {const now = Date.now()const diff = 现在 - 时间;时间 = 现在;如果(差异> 200){如果(e.deltaY <0){onScroll('向上')} 别的 {onScroll('向下')}}}功能 onScroll(方向){如果(方向 === '向上'){goSectionUp()} 别的 {goSectionDown()}};});

html {box-sizing: 边框框;溢出:隐藏;宽度:100%;高度:100%;}*,*:之前,*:之后{box-sizing:继承;}身体 {字体系列:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;填充:0;边距:0;溢出:隐藏;高度:100%;宽度:100%;位置:相对;}#页 {宽度:100%;高度:100%;过渡:全 1s 缓解;转换:无!重要;}.部分 {高度:100vh;宽度:100%;不透明度:0;可见性:隐藏;位置:绝对;顶部:0;左:0;过渡:所有 .7s 的缓入缓出;}.section:nth-of-type(1) {背景颜色:红色;}.section:nth-of-type(2) {背景颜色:海蓝宝石;}.section:nth-of-type(3) {背景颜色:蓝紫;}.section:nth-of-type(4) {}.积极的 {不透明度:1;可见性:可见;}#按钮 {位置:粘性;顶部:0;左:100px;z-索引:1000;}

<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.5/lodash.min.js"></script><div id="页面"><div class="section">one</div><div class="section">二</div><div class="section">三</div><div class="section">四</div>

解决方案

看起来你想要的是一个 debounce 函数.我建议使用这个,David Walsh:

function debounce(func,wait,immediate){变量超时;返回函数(){var context = this, args = arguments;后变后 = 函数(){超时=空;if (!immediate) func.apply(context, args);};var callNow = 立即 &&!超时;清除超时(超时);timeout = setTimeout(稍后,等待);if (callNow) func.apply(context, args);};};

使用

var myScrollFunction = debounce(function() {//你所做的所有繁重的工作}, 250);document.addEventListener('wheel', myScrollFunction);

要回答为什么您的代码没有按预期工作:鼠标滚轮在滚动时会产生一系列连续事件,因此您的时间差异始终小于200. 这是它正常"工作的一个例子(尽管最好的答案仍然是如上所述的真正的去抖动功能).

JSBin 示例https://jsbin.com/cuqacideto/edit?html,console,output

I'm making a simple full viewport scroller. You can change sections by triggering wheel event.

To prevent the eventhandler from firing many times in row and skipping pages, I've added a timer, calculating the difference between date.now() stored in variable and date.now() inside the eventHandler. This happens mostly if you spam scrolling, it makes you have to wait about 3 seconds to scroll again instead of 200ms. How to prevent this from happening?

document.ready = (fn) => {
  if (document.attachEvent ? document.readyState === "complete" : document.readyState !== "loading"){
    fn();
  } else {
    document.addEventListener('DOMContentLoaded', fn);
  }
}


document.ready(() => {

  const SECTIONS = document.querySelectorAll('.section');  
  let current;
  let onWheelTimeout = 'poop';
  let time = Date.now()
  
    // initialize first section as active
    _.first(SECTIONS).classList.add('active');
    
    document.addEventListener('wheel', onWheel)



  
  function goSectionUp() {
    const current = document.querySelector('.active');
    current.classList.remove('active');

    if(current.previousElementSibling) {
      current.previousElementSibling.classList.add('active');
    } else {
      _.last(SECTIONS).classList.add('active');
    }
  }
  
  function goSectionDown() {
    const current = document.querySelector('.active');
    current.classList.remove('active');

    if(current.nextElementSibling) {
      current.nextElementSibling.classList.add('active');
    } else {
      _.first(SECTIONS).classList.add('active');
    }
  }



  function onWheel(e) {
    const now = Date.now()
    const diff = now - time;
    time = now;
    if(diff > 200) {
      if(e.deltaY < 0) {
        onScroll('up')
      } else {
        onScroll('down')
      }
    }
  }

  function onScroll(direction) {
    if(direction === 'up') {
      goSectionUp()
    } else {
      goSectionDown()
    }
  };

});

html {
box-sizing: border-box;
overflow: hidden;
width: 100%; height: 100%;
}
*, *:before, *:after {
box-sizing: inherit;
}
body {
font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;
padding: 0; margin: 0;
overflow: hidden;
height: 100%; width: 100%;
position: relative;
}



#page {
  width: 100%; height: 100%;
  transition: all 1s ease; 
  transform: none !important;
}

.section {
  height: 100vh; width: 100%;
  opacity: 0;
  visibility: hidden;
  position: absolute;
  top: 0;
  left: 0;
  transition: all .7s ease-in-out;
}
.section:nth-of-type(1) {
  background-color: red;
}
.section:nth-of-type(2) {
  background-color: aquamarine;
}
.section:nth-of-type(3) {
  background-color: blueviolet;
}
.section:nth-of-type(4) {}

.active {
  opacity: 1; visibility: visible;
}


#button {
  position: sticky;
  top: 0; left: 100px;
  z-index: 1000;
}

<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.5/lodash.min.js"></script>
<div id="page">
  <div class="section">one</div>
  <div class="section">two</div>
  <div class="section">three</div>
  <div class="section">four</div>
</div>

解决方案

It seems like what you want is a debounce function. I'd recommend using this one, by David Walsh:

function debounce(func, wait, immediate) {
    var timeout;
    return function() {
        var context = this, args = arguments;
        var later = function() {
            timeout = null;
            if (!immediate) func.apply(context, args);
        };
        var callNow = immediate && !timeout;
        clearTimeout(timeout);
        timeout = setTimeout(later, wait);
        if (callNow) func.apply(context, args);
    };
};

Usage

var myScrollFunction = debounce(function() {
    // All the taxing stuff you do
}, 250);

document.addEventListener('wheel', myScrollFunction);

To answer why your code doesn't work as expected: The mouse wheel produces a series of continuous events while it is scrolling, so your time diff is constantly < 200. Here's an example of it working "properly" (though the best answer is still a true debounce function as stated above).

JSBin example https://jsbin.com/cuqacideto/edit?html,console,output

这篇关于事件处理程序被禁用的时间比预期的要长的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆