背景
jQuery的scrollTop()使用scrollTo(),这是一个即发即忘事件。没有滚动停止事件。滚动事件发生在scrollTo 的带外。 scrollTo 表示“开始滚动”,滚动事件表示“滚动(某个位置)”。 scrollTo 只是启动滚动的开始,它不保证返回时滚动完成。因此,jQuery 动画在最终滚动之前完成(甚至可能有多个滚动备份)。另一种方法是 jQuery 等待滚动的位置达到它所请求的位置(根据我的解决方案),但它不会这样做
如果有一个规范可以用来描述这一点,那就太好了,但它只是没有规范的 0 级 dom 元素之一,see here https://developer.mozilla.org/en-US/docs/Web/API/Window.scrollTo。我认为它的工作方式是有意义的,这就是为什么所有浏览器似乎都以这种方式实现它。
为什么会发生这种情况
动画最后滚动时发生以下情况:
- jquery: '窗口请滚动最后一点'
- 窗口:“我从 jquery 收到了这条滚动消息,我现在就开始滚动”
- jquery: 'woohoo 我完成了动画,我会完成'
- 你的代码:
lock = false;console.log("jump end");
- 窗口:“我已经滚动”调用滚动事件处理程序。
- 你的代码:
$(window).scroll(function (e) {
“为什么会发生这种事?”
正如您所看到的,jquery 在完成动画之前不会等待动画的最后滚动步骤完成(继续步骤 4)。部分原因是因为没有滚动停止事件,部分原因是 jquery 不会等待滚动位置到达所请求的位置。我们可以检测何时到达目的地位置,如下所述。
解决方案
滚动完成时没有停止事件。See here https://stackoverflow.com/questions/4620906/how-do-i-know-when-ive-stopped-scrolling-javascript。没有停止事件是有道理的,因为用户可以在任何时候再次开始滚动,因此滚动不会真正停止——用户可能只是暂停了几分之一秒。
用户滚动:对于用户滚动,正常的方法是等待一段时间以查看滚动是否完成,如引用问题的答案中所述(请记住用户可以再次开始滚动)。
滚动顶部:但是,由于我们知道要滚动到的位置,因此我们可以做得更好。
See 这把小提琴。 http://jsfiddle.net/47gLg/6/
关键在于,既然我们知道要滚动到哪里,我们就可以存储该位置。当我们到达那个位置时,我们知道我们已经完成了。
现在的输出是:
jump start
scroll animation
jump end
代码是(请注意,这是基于您的小提琴而不是编辑问题中的代码):
var scrollingTo = 0;
$('#id').click(function(event) {
if (scrollingTo) {
return;
}
console.log("jump start");
scrollingTo = 150;
$(jQuery.browser.webkit ? "body": "html").animate({ scrollTop: scrollingTo }, 150, function () {
});
});
function handleScroll()
{
if( scrollingTo !== 0 && $(window).scrollTop() == scrollingTo)
{
scrollingTo = 0;
console.log("jump end");
}
}
$(window).scroll(function (e) {
if (!scrollingTo){
console.log('user scroll');
} else {
console.log("scroll animation");
}
handleScroll();
});