由于 JavaScript 在与 UI 相同的线程中运行,滚动事件回调可能会阻塞 UI 线程,从而导致延迟。您需要限制滚动事件侦听器,因为某些浏览器会触发很多事件侦听器。特别是如果您在 OS X 上使用模拟滚动设备。由于您在侦听器中进行了大量高度计算,因此它会为每个触发的滚动事件触发重排(非常昂贵)。
要限制侦听器,您必须防止侦听器每次都触发。通常你会等到浏览器在 x 毫秒内没有触发事件,或者在调用你的回调之间有最短时间。尝试调整值以查看效果。即使是 0 毫秒也有帮助,因为它会延迟回调的执行,直到浏览器有时间(通常是 5-40 毫秒)。
切换类以在状态(静态和固定位置)之间切换而不是在 JavaScript 中对其进行硬编码也是一个好习惯。然后,您可以更清晰地分离关注点并避免潜在的额外重绘错误(请参阅“浏览器很聪明”部分)。(关于 jsfiddle 的示例)
等待 x 毫秒的暂停
// return a throttled function
function waitForPause(ms, callback) {
var timer;
return function() {
var self = this, args = arguments;
clearTimeout(timer);
timer = setTimeout(function() {
callback.apply(self, args);
}, ms);
};
}
this.start = function() {
// wrap around your callback
$window.scroll( waitForPause( 30, self.worker ) );
};
至少等待 x 毫秒(jsfiddle)
function throttle(ms, callback) {
var timer, lastCall=0;
return function() {
var now = new Date().getTime(),
diff = now - lastCall;
console.log(diff, now, lastCall);
if (diff >= ms) {
console.log("Call callback!");
lastCall = now;
callback.apply(this, arguments);
}
};
}
this.start = function() {
// wrap around your callback
$window.scroll(throttle(30, self.worker));
};
jQuery Waypoints
既然您已经在使用 jQuery,我会看看jQuery Waypoints插件,它为您的问题提供了一个简单而优雅的解决方案。只需在用户滚动到某个航点时定义一个回调。
示例:(jsfiddle)
$(document).ready(function() {
// throttling is built in, just define ms
$.waypoints.settings.scrollThrottle = 30;
$('#content').waypoint(function(event, direction) {
$(this).toggleClass('sticky', direction === "down");
event.stopPropagation();
}, {
offset: 'bottom-in-view' // checkpoint at bottom of #content
});
});