Make “scrollLeft” / “scrollTop” changes not trigger scroll event listener

前端 未结 5 644
刺人心
刺人心 2020-11-30 10:02

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 gr

相关标签:
5条回答
  • 2020-11-30 10:13

    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>

    0 讨论(0)
  • 2020-11-30 10:17

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

    0 讨论(0)
  • 2020-11-30 10:19

    You could try storing the offset top of your element and matching it against the scrollTop when you step inside 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 讨论(0)
  • 2020-11-30 10:31

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

    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.

    Thanks, all!

    0 讨论(0)
  • 2020-11-30 10:36

    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:

    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;
    
      ...
    }
    
    0 讨论(0)
提交回复
热议问题