如何消除JS / JQuery中的滚动事件?

问题描述 投票:1回答:2

滚动事件的触发方式比我想要的更多。如果向下滚动(后跟动画)并摆脱当前Element的.swap类,则它所要做的就是将.swap类赋予下一个同级对象。同样的东西只是向上。现在发生的是,基本上,如果向下/向上滚动,它会转到最后一个元素,第一个元素。

我已经尝试了Debouncing,Throtling和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>

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;
}
javascript jquery scroll debouncing
2个回答
0
投票

添加一些滚动距离阈值,即使现在滚动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)
}

0
投票

您不应为此使用滚动事件侦听器,最好使用Intersection Observer (IO)完成此操作。

如果要在一个以上的元素上触发动画,则通过滚动事件侦听器观看这些多个元素会导致性能下降。参见example this question。免责声明:这个问题也有我的答案。

为了以现代,高性能的方式解决此问题,最好为此使用Intersection Observer (IO)

有了IO,您可以观看一个(或多个)元素,并在它们出现或彼此相交时做出反应。

要使用IO,首先必须为其设置选项,然后定义要监视的元素,最后定义一旦IO触发将发生什么情况。

示例(Taken from here),进行了最小的修改:即使动画尚未发生,作者也删除了IO。我将unobserve调用移到了check元素是否可见的内部。

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="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>
© www.soinside.com 2019 - 2024. All rights reserved.