滚动事件触发太多次。我只希望它每秒最多触发一次

IT技术 javascript
2021-02-09 16:04:01

我有一个带有“无限滚动”的页面。它计算页面末尾和当前页面之间的差异,如果差异足够小,则加载更多内容。使用 jQuery 的代码是这样的:

$(window).on('scroll', function() {
    if (window.pageYOffset > loadMoreButton.offsetTop - 1000)
        # load more content via ajax
}

现在,问题是每次我滚动时,每次滚动都会多次触发此事件。我最多希望每 x 毫秒触发一次。我该怎么做?

6个回答

查看 Underscore.js 库的“throttle”方法。

http://underscorejs.org/#throttle

它给出的示例正是您要问的 - 限制您必须处理滚动事件的频率。

查看源代码下划线(这是非常好的记录),然后拉出油门。
2021-03-20 16:04:01
非常棒的库,但我试图避免任何依赖。
2021-03-22 16:04:01
2021-04-13 16:04:01

解决这个问题的一种方法是定义一个时间间隔,并且在该时间间隔内只处理一次滚动事件。如果在该时间间隔内出现多个滚动事件,则忽略它并仅在该时间间隔过去后处理它。

var scrollTimer, lastScrollFireTime = 0;

$(window).on('scroll', function() {

    var minScrollTime = 100;
    var now = new Date().getTime();

    function processScroll() {
        console.log(new Date().getTime().toString());
    }

    if (!scrollTimer) {
        if (now - lastScrollFireTime > (3 * minScrollTime)) {
            processScroll();   // fire immediately on first scroll
            lastScrollFireTime = now;
        }
        scrollTimer = setTimeout(function() {
            scrollTimer = null;
            lastScrollFireTime = new Date().getTime();
            processScroll();
        }, minScrollTime);
    }
});

这将立即触发第一个滚动事件,然后在滚动条移动时大约每 100 毫秒触发一次滚动事件,然后在滚动条停止移动后触发一个最终事件。您可以通过将参数更改为setTimeout(当前设置为 100)来调整事件的频率

这里有一个演示:http : //jsfiddle.net/jfriend00/EBEqZ/你需要打开一个调试控制台窗口,开始移动内容窗口中的滚动条,然后在调试控制台窗口中观察每个滚动事件的时间. 在我的 Chrome 版本中,它们的最小间隔设置为 100 毫秒,它们似乎每 100-200 毫秒发生一次。

@ user2356198 - 浏览器无法仅获取结束滚动事件。这种能力根本不存在。它会触发各种中间滚动事件,并且不会告诉您何时完成移动。因此,我们提出了使用计时器的变通方法,这些计时器试图猜测何时不再有滚动事件发生,因此必须结束。我建议你console.log($(window).scrollTop());在你的processScroll()方法中输出该修改旨在确保您不会processScroll()以相同的滚动位置连续调用两次。
2021-03-17 16:04:01
嗨 Jfriend,当我在无限页面上按键盘的“结束”键时,processScroll 似乎触发了两次。我该如何解决?
2021-03-18 16:04:01
@user2356198 - 这是一个解决这个问题的版本:jsfiddle.net/v8e7aLy6
2021-04-07 16:04:01
“结束”键没问题,但是当我快速向下滚动时,它会触发两次。慢速滚动没有问题。
2021-04-08 16:04:01

jQuery 的创建者 John Resig 有一个很酷的解释来解决这种情况。

var outerPane = $details.find(".details-pane-outer"),
    didScroll = false;

$(window).scroll(function() {
    didScroll = true;
});

setInterval(function() {
    if ( didScroll ) {
        didScroll = false;
        // Check your page position and then
        // Load in more results
    }
}, 250);

来源:http : //ejohn.org/blog/learning-from-twitter/

var isWorking = 0;

$(window).on('scroll', function()
{
    if(isWorking==0)  
    {
         isWorking=1;
         if (window.pageYOffset > loadMoreButton.offsetTop - 1000)
         # load more content via ajax
         setTimeout(function(){isWorking=0},1000);
    }
}
这可能会错过最后一个滚动事件,因为在滚动停止后,没有超时触发来处理最后一个滚动事件。
2021-03-23 16:04:01
oop 您不能在 javascript 中使用这样的睡眠功能。它会在睡眠期间挂起浏览器。Javascript 是单线程的并且会阻止浏览器。你就是不能写这样的 javascript 代码。
2021-03-28 16:04:01
我希望它的工作,没有测试它。它基本上启动每个滚动但如果另一个副本正在运行它不会做任何事情,如果不是它等待 xxx 毫秒并完成工作
2021-03-31 16:04:01
将其替换sleepsetTimeout(function(){isWorking=0},1000)它应该可以工作。
2021-04-04 16:04:01
var now = new Date().getTime();
$(window).scroll( function () {
    if (window.pageYOffset > loadMoreButton.offsetTop - 1000)
    {
        if (new Date().getTime() - now > 1000)
        {
            console.log("Task executed once per second");
            now = new Date().getTime();
        }
    }
});

或者

您可以使用节流函数调用: throttling-function-calls

function throttle(fn, threshhold, scope) {
  threshhold || (threshhold = 250);
  var last,
      deferTimer;
  return function () {
    var context = scope || this;

    var now = +new Date,
        args = arguments;
    if (last && now < last + threshhold) {
      // hold on to it
      clearTimeout(deferTimer);
      deferTimer = setTimeout(function () {
        last = now;
        fn.apply(context, args);
      }, threshhold);
    } else {
      last = now;
      fn.apply(context, args);
    }
  };
}

你可以这样称呼它:

$('body').on('mousemove', throttle(function (event) {
  console.log('tick');
}, 1000));
请为此代码添加一些注释和说明。
2021-03-17 16:04:01