JS/JQuery中的去抖动滚动事件是如何工作的?

3
滚动事件触发的次数比我想象中的多得多。它只需要在向下滚动时将.swap类赋给下一个同级元素(并附带动画效果),并且删除当前元素的.swap类。向上也是一样的。现在的情况是,如果向下/向上滚动,它基本上会跳到最后一个元素和第一个元素。这是一个单页应用,只在不同的div之间进行切换。
我已经尝试了去抖动(debouncing)、节流(throttling)和requestAnimationFrame,但到目前为止还没有成功。例如
非常感谢!
HTML:
<div class="div1 swap">
  <h1>Hello</h1>
</div>
<div class="div2">
  <h1>Stack</h1>
</div>
<div class="div3">
  <h1>Overflow</h1>
</div>
<div class="div4">
  <h1>Please</h1>
</div>
<div class="div5">
  <h1>Help</h1>
</div>

CSS:

.div1, .div2, .div3, .div4, .div5{
  visibility: hidden;
  position: fixed;
}
.swap{
  visibility: visible;
  -webkit-animation: slide-in-left .8s ease-out both;
          animation: slide-in-left .8s ease-out both;
}

JS:

window.onscroll = function(event) {
  var aktiv = document.querySelector('.swap');
  if(this.oldScroll > this.scrollY){
    console.log("Up");
    aktiv.previousElementSibling.classList.toggle('swap')
    aktiv.classList.toggle('swap')
  }
  else{
    console.log("Down");
    aktiv.nextElementSibling.classList.toggle('swap')
    aktiv.classList.toggle('swap')
  }
  this.oldScroll = this.scrollY;
}

1
你提到了去抖动(debouncing),能否分享一下你的去抖动尝试?基本上,去抖动与你现有的代码相同,但如果在一段时间内接收到多个事件,则只运行最后一个 - 也就是说,当它接收到一个事件时,会等待看是否还有其他事件即将到来,然后再触发去抖动操作。更多信息请参考:https://stackoverflow.com/tags/debouncing/info - freedomn-m
2个回答

1

为滚动距离添加一些阈值,因为现在即使您只滚动1像素,也会显示下一个元素。

window.onscroll = function(event) {
  var aktiv = document.querySelector('.swap');
  var diff = this.oldScroll - this.scrollY;
  var delta = 100; // Or some element height

  // If scolled too little - do nothing
  if (Match.abs(diff) <= delta) {
     return;
  }

  if(diff < 0){
    console.log("Up");
    aktiv.previousElementSibling.classList.toggle('swap')
    aktiv.classList.toggle('swap')
  }
  else{
    console.log("Down");
    aktiv.nextElementSibling.classList.toggle('swap')
    aktiv.classList.toggle('swap')
  }
  this.oldScroll = this.scrollY;
}

使用 setTimeout 来防抖事件:
var timer;

window.onscroll = function (event) {
    var self = this;
    clearTimeout(timer);
    timer = setTimeout(function () {
        [...rest of code...]
    }, 50)
}

当您向下滚动时,它运行得非常完美,但一旦尝试向上滚动,它只调用clearTimeout(timer);函数。 :( - fenrirmercenary

0

在编程中,你不应该使用滚动事件监听器,最好使用Intersection Observer (IO)

如果你想要触发多个元素的动画效果,通过滚动事件监听器来监视这些多个元素可能会导致性能问题。可以参考这个问题的例子。免责声明:这个问题也有我的答案。

为了以一种现代化、高效的方式解决这个问题,最好使用Intersection Observer (IO)

使用 IO,你可以监视一个或多个元素,并在它们进入视野或相互交叉时做出反应。

要使用 IO,首先必须设置其选项,然后定义要监视的元素,最后定义当 IO 触发时具体发生什么。

示例(来自此处)稍作修改:即使尚未发生动画,作者已删除了IO。我将未观察到的调用移至检查元素是否可见的内部。

const SELECTOR = '.watched';
const ANIMATE_CLASS_NAME = 'animated';

const animate = element => (
  element.classList.add(ANIMATE_CLASS_NAME)
);

const isAnimated = element => (
  element.classList.contains(ANIMATE_CLASS_NAME)
);

const intersectionObserver = new IntersectionObserver((entries, observer) => {
  entries.forEach((entry) => {
    
    // when element's is in viewport,
    // animate it!
    if (entry.intersectionRatio > 0) {
      animate(entry.target);
      // remove observer after animation
      observer.unobserve(entry.target);
    }
  });
});

// get only these elements,
// which are not animated yet
const elements = [].filter.call(
  document.querySelectorAll(SELECTOR),
  element => !isAnimated(element, ANIMATE_CLASS_NAME)
);
//console.log(elements);

// start observing your elements
elements.forEach((element) => intersectionObserver.observe(element));
.h100 {
height: 100vh;
}

.watched {
 opacity: 0;
 transition: opacity .5s;
}

.watched.animated {
opacity: 1;
}
<div class="watched hidden">
I'm watched and I'm in the viewport on page load!
</div>
<div class="h100">
scroll down
</div>
<div class="watched">
I'm watched
</div>
<div class="h100">
Another element, keep scrolling
</div>
<div class="watched">
I'm also watched
</div>


据我所理解,它会查找元素何时出现在视口中。问题是所有元素都始终在视口中,只是隐藏了而已。这是一个单页网站,使用小的滚动事件来触发下一个元素。很抱歉在描述中没有明确说明这些数据。我会添加的。非常感谢您的帮助! - fenrirmercenary
目前我的示例检查元素是否在视口中。如果我正确理解您的问题,您将不得不对其进行大量调整才能获得所需的结果。也许您可以看一下这个链接,它可能会帮到您:https://dev59.com/eVYO5IYBdhLWcg3wBtIp - cloned
感谢您的帮助和努力! :) - fenrirmercenary

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接