Сделать изменения "scrollLeft" / "scrollTop" не запускать прослушиватель событий прокрутки

14 Matchu [2009-09-06 23:51:00]

В настоящее время моя программа находится в месте, где он одновременно слушает, что пользователь прокручивает определенный элемент, но также порой автоматически прокручивает этот элемент сам по себе. (Не постепенный, симпатичный свиток, но мгновенный прыжок. Это имеет смысл в контексте, клянусь.)

Есть ли способ сделать событие прокрутки не срабатывающим, если прокрутка была выполнена путем установки scrollLeft или scrollTop? Моя первая мысль была основным переключателем, например:

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

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

но поскольку события не запускаются немедленно (oops, duhh), это не выполнимое решение. Какие еще ответы я мог бы попробовать? Я также использую jQuery, если это что-то помогает.

javascript jquery html


5 ответов


16 Решение Shog9 [2009-09-07 00:19:00]

Самый простой общий метод? Просто reset флаг в обработчике событий. Сначала вы захотите проверить, действительно ли вы меняете значение, так как иначе событие не будет запущено - как отмечает Родриго, хорошая практика здесь заключается в том, чтобы вытесните это так называемые "сеттерные" функции:

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

...

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

  if (ignore) return false;

  ...
}

Но, в зависимости от ваших потребностей, вы уже можете где-то хранить положение прокрутки; если да, просто обновите и проверьте это как свой флаг. Что-то вроде:

element.scrollLeft = currentScrollLeft = x;

...

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

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

  ...
}

2 Rodrigo [2009-09-07 00:21:00]

Как насчет сеттера?

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>


0 Colin [2009-09-07 00:18:00]

Вы можете попытаться сохранить верхнюю часть смещения вашего элемента и сопоставить его с scrollTop при входе в onScroll:

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
    }
}

0 Matchu [2009-09-07 00:53:00]

Хорошо, мое окончательное решение, построив Shog9 (не мой настоящий код, но мой подход):

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

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

Оператор if устанавливает флаг игнорирования, когда значение scrollLeft действительно заканчивается изменением, поэтому случаи, такие как установка от 0 до 0, не устанавливают флаг неверно.

Спасибо, все!