Chrome和IE上的Choppy/Laggy滚动事件

Mar*_*son 27 javascript jquery scroll google-chrome scrolltop

我试图让一个内容块始终显示给用户,即使他向下滚动页面.他还应该能够在内容块中上下滚动.这是一个带有精简版的小提琴,向您展示我的意思:

http://jsfiddle.net/9ehfV/2/

当向下滚动时,应该注意到,直到到达红色块的底部,它将把块固定在窗口上,当向上滚动时,它将它放回去.

在Firefox中,可以上下滚动,上面描述的固定/解除固定是不可察觉的 - 像丝绸一样光滑.

然而,一旦尝试在Chrome或IE中滚动,看起来滚动事件就会滞后,人们可以看到块"毛刺"一秒钟.这不是代码延迟 - 它似乎与浏览器有关.

有没有什么办法解决这一问题?我的智慧结束了.

我很欣赏有关如何以不同的方式达到同样效果的建议......谢谢

gre*_*ers 45

由于JavaScript在与UI相同的线程中运行,因此滚动事件回调可以阻止UI线程,从而导致延迟.您需要限制滚动事件侦听器,因为某些浏览器会激活它们.特别是如果你在OS X上使用模拟滚动设备.由于您在侦听器中执行了大量高度计算,因此会触发每次触发的滚动事件的重排(非常昂贵).

要限制侦听器,您必须每次都阻止侦听器触发.通常,您要等到浏览器不会触发x毫秒的事件,或者在调用回调之间有最短的时间.尝试调整值以查看效果.即使0毫秒也可以提供帮助,因为它会延迟回调的执行,直到浏览器有时间(通常为5-40毫秒).

切换类以在状态(静态和固定位置)之间切换而不是在JavaScript中对其进行硬编码也是一种很好的做法.然后,您可以更清晰地分离关注点,并避免错误的潜在额外重绘(请参阅"浏览器很智能"部分).(关于jsfiddle的例子)

等待x ms的暂停

// 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 ) );
};
Run Code Online (Sandbox Code Playgroud)

等待至少x ms(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));
};
Run Code Online (Sandbox Code Playgroud)

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
    });
});
Run Code Online (Sandbox Code Playgroud)

  • 这根本不能解决IE中的滞后问题.有时油门是你不需要的东西,例如,当你需要一个绝对定位的元素来跟随你的滚动,它必须是立即的.但不是在IE上. (5认同)
  • +1用于链接到航点.非常好. (3认同)
  • 这个答案可能会帮助人们解决不同的问题,但IE中的**波动/滞后滚动**动画不能通过限制滚动事件来解决. (3认同)
  • 原来如此.滚动逻辑比我第一次复杂一点.认为有必要在固定位置之间进行一些计算,但是类将简化固定位置.在这里更新了jsfiddle:http://jsfiddle.net/b5hU8/4/ (2认同)