在滚动时多次触发停止功能

时间:2014-04-18 14:24:12

标签: javascript jquery ajax

当用户滚动到底部时,下面的代码会加载下一页。但是,有时它会重复自己 - 当用户滚动太快时,或者在AJAX仍在加载时滚动。

有没有办法防止它多次发射?例如,在调用AJAX时无法加载任何内容,或者只能每秒调用一次AJAX?

任何帮助都会很棒。

 $(window).scroll(function() {

   if( $(window).scrollTop() + $(window).height() == $(document).height()) {

    if (firstURL !== null) {

      $.get(firstURL, function(html) { // this gets called multiple times on erratic scrolling
        firstURL = '';
        var q = $(html).find('.post');
        l = $(html).filter('div.bottom-nav');
        if( l[0].childNodes.length > 0 ){
            firstURL = l[0].children[0].getAttribute('href');
        } else {
          firstURL =  null;
        }

          q.imagesLoaded( function() {
            jQuery(".content").append(q).masonry( 'appended', q, true );
           });
      });
       }
   }
});

5 个答案:

答案 0 :(得分:10)

只需添加一个标志:

var ready = true; //Assign the flag here

$(window).scroll(function() {
    //Check the flag here. Check it first, it's better performance wise.
    if(ready && $(window).scrollTop() + $(window).height() == $(document).height()) { 
        ready = false; //Set the flag here

        if (firstURL !== null) {

            $.get(firstURL, function(html) { // this gets called multiple times on erratic scrolling

                firstURL = '';
                var q = $(html).find('.post');
                l = $(html).filter('div.bottom-nav');
                if( l[0].childNodes.length > 0 ){
                    firstURL = l[0].children[0].getAttribute('href');
                } else {
                    firstURL =  null;
                }

                q.imagesLoaded( function() {
                    jQuery(".content").append(q).masonry( 'appended', q, true );
                });
            }).always(function(){
                ready = true; //Reset the flag here
            });
        }
    }
});

答案 1 :(得分:0)

我有一个类似的问题,滚动窗口多次触发我的函数(manupulating img slider的属性)。为了有效地解决这个问题,您可以推迟执行滚动处理程序,并且使用额外的'页面滚动'标记以防止多个处理程序调用。 看看下面的例子,你肯定可以为你的案例添加方法。

$(function()
{
    var pageFold = 175; //scrolling threshold

    var doScroll = false; //init
    var timeoutScroll = 100; //delay

    var windowScrolled = false; //initial scrolling indicatior
    var windowScrolling = false; //current scrolling status indicator

    //load next page handler
    function loadNextPage()
    {
        if(windowScrolling != true)
        { 
           //and do ajax stuff - your code
        }
    }

   //check if page scrolled below threshold handler
   function foldedBelow()
   {
        //nice scrolled px amount detection
        return (Math.max($('body').scrollTop(), $('html').scrollTop()) > pageFold);
   }

   //actual scrolled handler
   function doWindowScroll()
   {
        windowScrolled = true;
        if(foldedBelow())
        {
                    loadNextPage();
        }
        windowScrolling = false;
   }

    //deffered scroll hook
    $(window).scroll(function(e){
        windowScrolling = true;
        clearTimeout(doScroll);
        doScroll = setTimeout(doWindowScroll, timeoutScroll);

    });   
});

答案 2 :(得分:0)

当我做这样的事情时,我实现了一个调用自定义scrolled_to_bottom - 事件的定时滚动处理程序。

(function($, window, document){
    "use strict";

    var $document = $(document);
    var $window = $(window);

    var _throttleTimer = null;
    var _throttleDelay = 100;

    function ScrollHandler(event) {
        //throttle event:
        clearTimeout(_throttleTimer);
        _throttleTimer = setTimeout(function () {
            if ($window.scrollTop() + $window.height()  > $document.height() - 400) {
                console.log('fire_scrolled_to_bottom');
                $document.trigger('scrolled_to_bottom');
            }

        }, _throttleDelay);
    }

    $document.ready(function () {
        $window
            .off('scroll', ScrollHandler)
            .on('scroll', ScrollHandler);

    });
}(jQuery, window, document));

然后在我的对象处理重新加载时,我用标志检查绑定了该事件,如果它已经加载了。

handler = {
        ...,
    isLoading: false,
    bind: {
        var self = this;
        $document.on('scrolled_to_bottom', function () {
            if (self.isLoading) {

                return;
            }

            self.nextPage();
        });

    }
    nextPage(): function () {
        var self = this;
        this.isLoading = true;

        $.ajax({
            url: url,
            data: self.searchData,
            dataType: "json",
            type: "POST",
            success: function (json) {
                // do what you want with respone
            },
            error: function (xhr, statusText, errorThrown) {
                bootbox.alert('An error occured.');
            },
            complete: function () {
                self.isLoading = false;
            }
        });
    },
    init: function () {
        this.doInitStuff();
        this.bind();
    }
}

通过这种方式,我分离了关注点并可以很好地重用触发器,并且如果在重新加载时发生其他事情,则可以轻松添加功能。

答案 3 :(得分:0)

尝试存储某种数据,用于存储页面当前是否正在加载新项目。也许是这样的:

$(window).data('ajaxready', true).scroll(function(e) {
    if ($(window).data('ajaxready') == false) return;

    if ($(window).scrollTop() >= ($(document).height() - $(window).height())) {
        $('div#loadmoreajaxloader').show();
        $(window).data('ajaxready', false);
        $.ajax({
            cache: false,
            url: 'loadmore.php?lastid=' + $('.postitem:last').attr('id'),
            success: function(html) {
                if (html) {
                    $('#postswrapper').append(html);
                    $('div#loadmoreajaxloader').hide();
                } else {
                    $('div#loadmoreajaxloader').html();
                }
                $(window).data('ajaxready', true);
            }
        });
    }
});

在发送Ajax请求之前,会清除一个标志,表示该文档尚未准备好接收更多Ajax请求。一旦Ajax成功完成,它就会将标志设置为true,并且可以触发更多请求。

复制:jQuery Infinite Scroll - event fires multiple times when scrolling is fast

答案 4 :(得分:0)

这是我的解决方案。您可以获得一个想法并将其应用到您的想法。也是为了帮助别人。

  • 您可以先使用条件执行您的方法:if(loadInterval === 空值)。这意味着如果我们已经等了5秒钟。
  • 分配loadInterval = setTimeout(),然后在5秒后使变量无效。

以下是示例代码。

      //declare outside
      var loadInterval = null;
      // ..... 
      // .....
  $(window).scroll(function() {

    if ($('.loadmore').isOnScreen() === true) {

      //No waiting registered, we can run loadMore
      if(loadInterval === null) {

        // This console.log executes in 5 seconds interval
        console.log('Just called ' + new Date());
        //  your code in here is prevented from running many times on scroll

        // Register setTimeout() to wait for some seconds. 
        // The code above will not run until this is nullified
        loadInterval = setTimeout(function(){
            //Nullified interval after 5 seconds
            loadInterval = null;}
        , 5000);  
      }
    }
  });

我在这里发布了jQuery的IsOnScreen()插件(我发现它在stackoverflow上:)

$.fn.isOnScreen = function() {

  var win = $(window);

  var viewport = {
    top: win.scrollTop(),
    left: win.scrollLeft()
  };
  viewport.right = viewport.left + win.width();
  viewport.bottom = viewport.top + win.height();

  var bounds = this.offset();
  bounds.right = bounds.left + this.outerWidth();
  bounds.bottom = bounds.top + this.outerHeight();

  return (!(viewport.right < bounds.left || viewport.left > bounds.right || viewport.bottom < bounds.top || viewport.top > bounds.bottom));

};