Javascript 滚动事件触发次数过多。我只希望它最多每秒发射一次
我有一个“无限卷轴”的页面。它计算页面结尾与当前页面之间的差异,如果差异足够小,则加载更多内容。使用jQuery时,代码如下所示:Javascript 滚动事件触发次数过多。我只希望它最多每秒发射一次,javascript,Javascript,我有一个“无限卷轴”的页面。它计算页面结尾与当前页面之间的差异,如果差异足够小,则加载更多内容。使用jQuery时,代码如下所示: $(window).on('scroll', function() { if (window.pageYOffset > loadMoreButton.offsetTop - 1000) # load more content via ajax } 现在,问题是每次我滚动时,每个滚动都会触发多次此事件。我希望最多每x毫秒开火一次。我该
$(window).on('scroll', function() {
if (window.pageYOffset > loadMoreButton.offsetTop - 1000)
# load more content via ajax
}
现在,问题是每次我滚动时,每个滚动都会触发多次此事件。我希望最多每x毫秒开火一次。我该如何做到这一点?查看underline.js库的“throttle”方法
它给出的示例正是您所要求的-限制您必须处理滚动事件的频率。多次滚动触发是正确的,您应该能够每次获得不同的滚动位置。我认为当你第一次进入滚动事件时,你需要设置一个计时器,就像你提到的x毫秒,同时记录时间戳,然后下次滚动事件触发时,检查最后的触发时间,如果在x毫秒内,则忽略它,解决此问题的一种方法是定义一个时间间隔,并在该时间间隔内仅处理一次滚动事件。如果在该时间间隔内出现多个滚动事件,则忽略它并仅在该时间间隔结束时处理它
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);
}
}
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);
}
});
这将立即触发第一个滚动事件,然后在滚动条移动时大约每100ms触发一次滚动事件,然后在滚动条停止移动后触发最后一个事件。您可以通过将参数更改为setTimeout
(当前设置为100)来调整事件的频率
这里有一个演示:您需要打开调试控制台窗口,开始在内容窗口中移动滚动条,然后在调试控制台窗口中观察每个滚动事件的时间。在我的Chrome版本中,它们的最小间隔设置为100ms,并且似乎每100-200ms出现一次
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();
}
}
});
或
您可以使用节流功能调用:
这里有一个解决方案,它不需要使用额外的JS库或插件,目的是简单。它可能没有其他实现那么有效,但它肯定比每次滚动时触发主事件更有效 这是Danny Van Kooten从这张照片上取的。我用它来延迟我博客上返回顶部按钮的
onscroll()
事件
var timer;
$(window).scroll(function() {
if(timer) {
window.clearTimeout(timer);
}
timer = window.setTimeout(function() {
// actual code here. Your call back function.
console.log( "Firing!" );
}, 100);
});
您还可以通过将变量移出回调函数来进一步提高性能,以避免不必要的重新计算,例如$(window).height()
的值或加载页面后不会更改的某些静态div元素的高度
下面是一个根据我的用例改编的示例
var scrollHeight = $("#main-element").height(); //never changes, no need to recalculate.
$(window).on('scroll', function() {
if (timer)
window.clearTimeout(timer);
timer = window.setTimeout(function() {
var scrollPosition = $(window).height() + $(window).scrollTop();
if ($(window).scrollTop() < 500)
$(".toggle").fadeIn(800);
else
$(".toggle").fadeOut(800);
}, 150); //only fire every 150 ms.
});
var scrollHeight=$(“#main元素”).height()//永不改变,无需重新计算。
$(窗口).on('scroll',function(){
中频(定时器)
清除超时(计时器);
timer=window.setTimeout(函数(){
var scrollPosition=$(窗口).height()+$(窗口).scrollTop();
如果($(窗口).scrollTop()<500)
$(“.toggle”).fadeIn(800);
其他的
$(“.toggle”).fadeOut(800);
},150);//仅每150毫秒点火一次。
});
这将实际功能限制为仅每150ms执行一次,否则,如果未超过150ms,则将计时器重置回0。调整值以满足您的需要 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);
资料来源:
一个好的油门功能不需要大量的局部变量。节流功能的目的是减少浏览器资源,而不是应用太多的开销,使您使用的浏览器资源更多。为了证明这一点,我设计了一个节流函数,它的作用域中只有5个“挂起”变量引用。此外,我对油门功能的不同使用需要许多不同的环境。这是我的清单,我相信'好'油门功能需要的东西
- 如果自上次调用以来间隔超过毫秒,则立即调用该函数
- 避免为另一个间隔MS执行函数
- 延迟过多的事件触发,而不是完全删除事件
- 在连续调用时更新延迟事件对象,使其不会变为“过时”
function throttle(func, alternateFunc, minimumInterval) {
var executeImmediately = true, freshEvt = null;
return function(Evt) {
if (executeImmediately) { // Execute immediatly
executeImmediately = false;
setTimeout(function(f){ // handle further calls
executeImmediately = true;
if (freshEvt !== null) func( freshEvt );
freshEvt = null;
}, minimumInterval);
return func( Evt );
} else { // Delayed execute
freshEvt = Evt;
if (typeof alternateFunc === "function") alternateFunc( Evt );
}
};
}
然后,要围绕DOM事件侦听器包装此节流函数,请执行以下操作:
var ltCache = [];
function listen(obj, evt, func, _opts){
var i = 0, Len = ltCache.length, lF = null, options = _opts || {};
a: {
for (; i < Len; i += 4)
if (ltCache[i] === func &&
ltCache[i+1] === (options.alternate||null) &&
ltCache[i+2] === (options.interval||200)
) break a;
lF = throttle(func, options.alternate||null, options.interval||200);
ltCache.push(func, options.alternate||null, options.interval||200, lF);
}
obj.addEventListener(evt, lF || ltCache[i+3], _opts);
};
function mute(obj, evt, func, options){
for (var i = 0, Len = ltCache.length; i < Len; i += 4)
if (ltCache[i] === func &&
ltCache[i+1] === (options.alternate||null) &&
ltCache[i+2] === (options.interval||200)
) return obj.removeEventListener(evt, ltCache[i+3], options);
}
var ltCache=[];
函数侦听(obj、evt、func、_opts){
var i=0,Len=ltCache.length,lF=null,options=_opts |{};
a:{
对于(;i
用法示例:
功能节流阀(func、alternateFunc、minimumInterval){
var executeImmediately=true,freshvt=null;
函数handleFurtherCalls(f){
executeImmediately=true;
if(freshvt!==null)func(freshvt);
freshvt=null;
};
返回函数(Evt){
如果(executeImmediately){//立即执行
executeImmediately=false;
设置超时(handleFurtherCalls,minimumInterval);
function throttle(func, alternateFunc, minimumInterval) {
var executeImmediately = true, freshEvt = null;
return function(Evt) {
if (executeImmediately) { // Execute immediatly
executeImmediately = false;
setTimeout(function(f){ // handle further calls
executeImmediately = true;
if (freshEvt !== null) func( freshEvt );
freshEvt = null;
}, minimumInterval);
return func( Evt );
} else { // Delayed execute
freshEvt = Evt;
if (typeof alternateFunc === "function") alternateFunc( Evt );
}
};
}
var ltCache = [];
function listen(obj, evt, func, _opts){
var i = 0, Len = ltCache.length, lF = null, options = _opts || {};
a: {
for (; i < Len; i += 4)
if (ltCache[i] === func &&
ltCache[i+1] === (options.alternate||null) &&
ltCache[i+2] === (options.interval||200)
) break a;
lF = throttle(func, options.alternate||null, options.interval||200);
ltCache.push(func, options.alternate||null, options.interval||200, lF);
}
obj.addEventListener(evt, lF || ltCache[i+3], _opts);
};
function mute(obj, evt, func, options){
for (var i = 0, Len = ltCache.length; i < Len; i += 4)
if (ltCache[i] === func &&
ltCache[i+1] === (options.alternate||null) &&
ltCache[i+2] === (options.interval||200)
) return obj.removeEventListener(evt, ltCache[i+3], options);
}