使“scrollLeft”/“scrollTop”更改不会触发滚动事件侦听器

时间:2022-11-28 15:01:08

Currently my program is in a spot where it both listens for the user to scroll a certain element, but also, at times, automatically scrolls this element by itself. (Not a gradual, pretty scroll, but an instant jump. It makes sense in context, I swear.)

目前我的程序位于一个位置,它既可以监听用户滚动某个元素,也可以自动滚动这个元素。 (不是一个渐进的,漂亮的卷轴,而是瞬间跳跃。我发誓在上下文中有道理。)

Is there a way to make the scroll event not trigger if the scrolling was done by setting scrollLeft or scrollTop? My first thought was a basic switch, like:

如果通过设置scrollLeft或scrollTop完成滚动,有没有办法使滚动事件不触发?我的第一个想法是一个基本的开关,如:

ignoreScrollEvents = true;
element.scrollLeft = x;
ignoreScrollEvents = false;

function onScroll() {
  if(ignoreScrollEvents) return false;
}

but since events don't trigger immediately (oops, duhh), that's not a workable solution. What other sort of answers could I try? I'm also using jQuery, if that helps anything.

但由于事件不会立即触发(oops,duhh),这不是一个可行的解决方案。我可以尝试其他什么样的答案?我也在使用jQuery,如果这有帮助的话。

5 个解决方案

#1


19  

Easiest generic method? Just reset the flag in the event handler. You'll want to check first if you're actually changing the value, as otherwise an event won't be fired - as Rodrigo notes, a good practice here is to factor this out into so-called "setter" functions:

最简单的通用方法?只需重置事件处理程序中的标志即可。如果您实际上正在更改值,您将首先检查,否则事件将不会被触发 - 正如Rodrigo所说,这里的一个好习惯是将其分解为所谓的“setter”函数:

function setScrollLeft(x)
{
  if ( element.scrollLeft != x )
  {
    ignoreScrollEvents = true;
    element.scrollLeft = x;
  }
} 

...

function onScroll() 
{
  var ignore = ignoreScrollEvents;
  ignoreScrollEvents = false;

  if (ignore) return false;

  ...
}

But, depending on your needs, you may already be storing the scroll position somewhere; if so, just update and check that as your flag. Something like:

但是,根据您的需要,您可能已经将滚动位置存储在某处;如果是这样,只需更新并检查它作为您的标志。就像是:

element.scrollLeft = currentScrollLeft = x;

...

function onScroll() 
{
  // retrieve element, etc... 

  if (element.scrollLeft == currentScrollLeft) return false;

  ...
}

#2


2  

How about a setter?

安装者怎么样?

var _preventEvent = false; // set global flag 

function setScrollTop(amount) {
  _preventEvent = true; // set flag
  document.documentElement.scrollTop = amount * Math.random();
}

function setScrollLeft(amount) {
  _preventEvent = true; // set flag
  document.documentElement.scrollLeft = amount * Math.random();
}

// scroll event listener
window.onscroll = function() {
  console.clear();
  
  if (_preventEvent) {
    _preventEvent = false; // reset flag
    return;
  }
  
  console.log('normal scroll');
}
html{ height:500%; width:500%; } 
button{ position:fixed; }
button + button{ top:50px; }  
<button onclick=setScrollTop(1000)>Random scrollTop</button>
<button onclick=setScrollLeft(1000)>Random scrollLeft</button>

#3


1  

You could constantly check if the scroll position changes...

您可以不断检查滚动位置是否发生变化......

#4


0  

You could try storing the offset top of your element and matching it against the scrollTop when you step inside onScroll:

您可以尝试存储元素的偏移顶部,并在执行onScroll时将其与scrollTop匹配:

function onScroll(){
    var scrollTop = (document.documentElement.scrollTop || document.body.scrollTop),
    offsetTop = $('selector').offset().top;
    if(offsetTop > scrollTop){
      //user has not scrolled to element so do auto scrolling
    }
}

#5


0  

All right, my final solution, building off of Shog9 (not my real code, but my approach):

好吧,我的最终解决方案,建立Shog9(不是我真正的代码,但我的方法):

var oldScrollLeft = element.scrollLeft;
element.scrollLeft = x;
if(element.scrollLeft != oldScrollLeft) {
  ignoreScrollEvents = true;
}

function onScroll() {
  if(!ignoreScrollEvents) performGreatActions();
  ignoreScrollEvents = false;
}

The if statement only sets the ignore flag when the scrollLeft value actually ends up changing, so cases like setting from 0 to 0 don't set the flag incorrectly.

if语句仅在scrollLeft值实际结束更改时设置ignore标志,因此设置从0到0的情况不会错误地设置标志。

Thanks, all!

谢谢,全部!

#1


19  

Easiest generic method? Just reset the flag in the event handler. You'll want to check first if you're actually changing the value, as otherwise an event won't be fired - as Rodrigo notes, a good practice here is to factor this out into so-called "setter" functions:

最简单的通用方法?只需重置事件处理程序中的标志即可。如果您实际上正在更改值,您将首先检查,否则事件将不会被触发 - 正如Rodrigo所说,这里的一个好习惯是将其分解为所谓的“setter”函数:

function setScrollLeft(x)
{
  if ( element.scrollLeft != x )
  {
    ignoreScrollEvents = true;
    element.scrollLeft = x;
  }
} 

...

function onScroll() 
{
  var ignore = ignoreScrollEvents;
  ignoreScrollEvents = false;

  if (ignore) return false;

  ...
}

But, depending on your needs, you may already be storing the scroll position somewhere; if so, just update and check that as your flag. Something like:

但是,根据您的需要,您可能已经将滚动位置存储在某处;如果是这样,只需更新并检查它作为您的标志。就像是:

element.scrollLeft = currentScrollLeft = x;

...

function onScroll() 
{
  // retrieve element, etc... 

  if (element.scrollLeft == currentScrollLeft) return false;

  ...
}

#2


2  

How about a setter?

安装者怎么样?

var _preventEvent = false; // set global flag 

function setScrollTop(amount) {
  _preventEvent = true; // set flag
  document.documentElement.scrollTop = amount * Math.random();
}

function setScrollLeft(amount) {
  _preventEvent = true; // set flag
  document.documentElement.scrollLeft = amount * Math.random();
}

// scroll event listener
window.onscroll = function() {
  console.clear();
  
  if (_preventEvent) {
    _preventEvent = false; // reset flag
    return;
  }
  
  console.log('normal scroll');
}
html{ height:500%; width:500%; } 
button{ position:fixed; }
button + button{ top:50px; }  
<button onclick=setScrollTop(1000)>Random scrollTop</button>
<button onclick=setScrollLeft(1000)>Random scrollLeft</button>

#3


1  

You could constantly check if the scroll position changes...

您可以不断检查滚动位置是否发生变化......

#4


0  

You could try storing the offset top of your element and matching it against the scrollTop when you step inside onScroll:

您可以尝试存储元素的偏移顶部,并在执行onScroll时将其与scrollTop匹配:

function onScroll(){
    var scrollTop = (document.documentElement.scrollTop || document.body.scrollTop),
    offsetTop = $('selector').offset().top;
    if(offsetTop > scrollTop){
      //user has not scrolled to element so do auto scrolling
    }
}

#5


0  

All right, my final solution, building off of Shog9 (not my real code, but my approach):

好吧,我的最终解决方案,建立Shog9(不是我真正的代码,但我的方法):

var oldScrollLeft = element.scrollLeft;
element.scrollLeft = x;
if(element.scrollLeft != oldScrollLeft) {
  ignoreScrollEvents = true;
}

function onScroll() {
  if(!ignoreScrollEvents) performGreatActions();
  ignoreScrollEvents = false;
}

The if statement only sets the ignore flag when the scrollLeft value actually ends up changing, so cases like setting from 0 to 0 don't set the flag incorrectly.

if语句仅在scrollLeft值实际结束更改时设置ignore标志,因此设置从0到0的情况不会错误地设置标志。

Thanks, all!

谢谢,全部!