在jquery scrollTop动画完成后,滚动触发

时间:2022-04-18 10:57:18

Why does another scroll event get called after a scrollTop animation fires its complete callback?

为什么在scrollTop动画触发它的完整回调之后会调用另一个滚动事件?

Click Handler:

单击处理程序:

var lock = false;

$('#id').click(function(event) {
    var pos;
    if (lock) {
        return;
    }
    lock = true;
    pos = 150;

    console.log("jump start");

    $(jQuery.browser.webkit ? "body": "html").animate({ scrollTop: pos }, 150, function () {
        lock = false;
        console.log("jump end");
    });
});

Scroll Handler:

滚动处理程序:

$(window).scroll(function (e) {
    console.log("scrolling");

    if (!lock){
        alert('1');
    }
});

Log:

日志:

jump start
scrolling
jump end
scrolling

demo on jsfiddle

演示在jsfiddle

2 个解决方案

#1


10  

Background

背景

jQuery scrollTop() uses scrollTo() which is a fire and forget event. There is no stopped event for scrolling. The scroll events occur out of band from scrollTo. scrollTo means 'start scroll', a scroll event means 'scrolled (some position)'. scrollTo just initiates the starting of the scroll, it doesn't guarantee that scrolling finished when it returns. So, jQuery animation completes before final scroll (there could even be multiple scrolls backed up). The alternative would be for jQuery to wait for the position of the scroll to be what it requested (per my soln), but it does not do this

jQuery scrollTop()使用了scrollTo(),这是一个fire和forget事件。滚动没有停止事件。滚动事件发生在滚动条的带外。scrollTo的意思是“开始滚动”,滚动事件的意思是“滚动(某个位置)”。scrollTo只是开始滚动的开始,它并不保证在返回时滚动结束。因此,jQuery动画在最终滚动之前完成(甚至可能备份多个滚动)。另一种选择是让jQuery等待滚动的位置是它所请求的(根据我的soln),但它不会这么做

It would be nice if there was a specification that we could point to describing this, but it is just one of the Level 0 dom elements without a spec, see here. I think it makes sense the way that it works, which is why all browsers seem to implement it this way.

如果有一个规范我们可以指出来描述它,那就太好了,但是它只是没有规范的0级dom元素之一,请参见这里。我认为它的工作方式是有意义的,这就是为什么所有浏览器似乎都以这种方式实现它。

Why is this happening

为什么会这样

The following occurs on the last scroll of the animation:

在动画的最后一卷中出现以下内容:

  1. jquery: 'Window please scroll this last bit'
  2. jquery:“窗口请滚动最后一点”
  3. Window: 'I got this message from jquery to scroll I will start that now'
  4. 窗口:“我从jquery得到这个消息,我现在就开始。”
  5. jquery: 'woohoo I am finished the animation, I will complete'
  6. jquery:“我完成动画了,我完成了”
  7. Your code: lock = false;console.log("jump end");
  8. 您的代码:lock = false;控制台。日志(“跳结束”);
  9. Window: 'I have scrolled' call scroll event handlers.'
  10. 窗口:“我已经滚动了”调用滚动事件处理程序。
  11. Your code: $(window).scroll(function (e) { 'Why is this happening?'
  12. 代码:$(窗口)。滚动(函数e){'为什么会这样?'

As you can see jquery does not wait for the final scroll step of the animation to complete before completing the animation (going on to step 4). Partly this is because there is no stopped event for scrolling and partly this is because jquery does not wait for the scroll position to reach the position that was requested. We can detect when we have reached the destination position as described below.

正如你所看到的jquery不等待的最后一步滚动动画完成之前完成动画(在步骤4)。这部分是因为没有停止事件滚动和这部分是因为jquery不等待滚动位置达到要求的位置。当我们到达目的地位置时,我们可以检测如下所述。

Solutions

解决方案

There is no stopped event for when scrolling completes. See here. It makes sense that there is no stopped event because the user could start scrolling again at any point, so there is no point where scrolling has really stopped - the user might just have paused for a fraction of a second.

滚动完成时没有停止事件。在这里看到的。没有停止事件是合理的,因为用户可以在任何点重新开始滚动,所以滚动没有真正停止的意义——用户可能只是暂停了几秒钟。

User scrolling: For user scrolling, the normal approach is to wait some amount of time to see if scrolling is complete as described in the answer of the referenced question (bearing in mind that the user could start scrolling again).

用户滚动:对于用户滚动,通常的方法是等待一段时间,看看滚动是否如引用问题的答案中所描述的那样完成(记住用户可以重新开始滚动)。

scrollTop: However, since we know the position that we are scrolling to we can do better.

不过,既然我们知道要滚动到的位置,我们可以做得更好。

See this fiddle.

看到这个小提琴。

The crux of it is that since we know where we are scrolling to, we can store that position. When we reach that position we know that we are done.

问题的关键在于,既然我们知道要滚动到哪里,就可以存储这个位置。当我们达到那个位置时,我们就知道我们完了。

The output is now:

输出:

jump start
scroll animation
jump end

The code is (note that this is based off your fiddle rather than the code in the edited question):

代码是(注意,这是基于您的小提琴而不是编辑的问题中的代码):

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();
});

#2


0  

I believe that at the time the animation ends and the callback function is called, the event has not reached the window yet, so it is not re-called, it just hasn't been fired yet.

我相信在动画结束和回调函数被调用的时候,事件还没有到达窗口,所以它没有被重新调用,它只是还没有被触发。

#1


10  

Background

背景

jQuery scrollTop() uses scrollTo() which is a fire and forget event. There is no stopped event for scrolling. The scroll events occur out of band from scrollTo. scrollTo means 'start scroll', a scroll event means 'scrolled (some position)'. scrollTo just initiates the starting of the scroll, it doesn't guarantee that scrolling finished when it returns. So, jQuery animation completes before final scroll (there could even be multiple scrolls backed up). The alternative would be for jQuery to wait for the position of the scroll to be what it requested (per my soln), but it does not do this

jQuery scrollTop()使用了scrollTo(),这是一个fire和forget事件。滚动没有停止事件。滚动事件发生在滚动条的带外。scrollTo的意思是“开始滚动”,滚动事件的意思是“滚动(某个位置)”。scrollTo只是开始滚动的开始,它并不保证在返回时滚动结束。因此,jQuery动画在最终滚动之前完成(甚至可能备份多个滚动)。另一种选择是让jQuery等待滚动的位置是它所请求的(根据我的soln),但它不会这么做

It would be nice if there was a specification that we could point to describing this, but it is just one of the Level 0 dom elements without a spec, see here. I think it makes sense the way that it works, which is why all browsers seem to implement it this way.

如果有一个规范我们可以指出来描述它,那就太好了,但是它只是没有规范的0级dom元素之一,请参见这里。我认为它的工作方式是有意义的,这就是为什么所有浏览器似乎都以这种方式实现它。

Why is this happening

为什么会这样

The following occurs on the last scroll of the animation:

在动画的最后一卷中出现以下内容:

  1. jquery: 'Window please scroll this last bit'
  2. jquery:“窗口请滚动最后一点”
  3. Window: 'I got this message from jquery to scroll I will start that now'
  4. 窗口:“我从jquery得到这个消息,我现在就开始。”
  5. jquery: 'woohoo I am finished the animation, I will complete'
  6. jquery:“我完成动画了,我完成了”
  7. Your code: lock = false;console.log("jump end");
  8. 您的代码:lock = false;控制台。日志(“跳结束”);
  9. Window: 'I have scrolled' call scroll event handlers.'
  10. 窗口:“我已经滚动了”调用滚动事件处理程序。
  11. Your code: $(window).scroll(function (e) { 'Why is this happening?'
  12. 代码:$(窗口)。滚动(函数e){'为什么会这样?'

As you can see jquery does not wait for the final scroll step of the animation to complete before completing the animation (going on to step 4). Partly this is because there is no stopped event for scrolling and partly this is because jquery does not wait for the scroll position to reach the position that was requested. We can detect when we have reached the destination position as described below.

正如你所看到的jquery不等待的最后一步滚动动画完成之前完成动画(在步骤4)。这部分是因为没有停止事件滚动和这部分是因为jquery不等待滚动位置达到要求的位置。当我们到达目的地位置时,我们可以检测如下所述。

Solutions

解决方案

There is no stopped event for when scrolling completes. See here. It makes sense that there is no stopped event because the user could start scrolling again at any point, so there is no point where scrolling has really stopped - the user might just have paused for a fraction of a second.

滚动完成时没有停止事件。在这里看到的。没有停止事件是合理的,因为用户可以在任何点重新开始滚动,所以滚动没有真正停止的意义——用户可能只是暂停了几秒钟。

User scrolling: For user scrolling, the normal approach is to wait some amount of time to see if scrolling is complete as described in the answer of the referenced question (bearing in mind that the user could start scrolling again).

用户滚动:对于用户滚动,通常的方法是等待一段时间,看看滚动是否如引用问题的答案中所描述的那样完成(记住用户可以重新开始滚动)。

scrollTop: However, since we know the position that we are scrolling to we can do better.

不过,既然我们知道要滚动到的位置,我们可以做得更好。

See this fiddle.

看到这个小提琴。

The crux of it is that since we know where we are scrolling to, we can store that position. When we reach that position we know that we are done.

问题的关键在于,既然我们知道要滚动到哪里,就可以存储这个位置。当我们达到那个位置时,我们就知道我们完了。

The output is now:

输出:

jump start
scroll animation
jump end

The code is (note that this is based off your fiddle rather than the code in the edited question):

代码是(注意,这是基于您的小提琴而不是编辑的问题中的代码):

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();
});

#2


0  

I believe that at the time the animation ends and the callback function is called, the event has not reached the window yet, so it is not re-called, it just hasn't been fired yet.

我相信在动画结束和回调函数被调用的时候,事件还没有到达窗口,所以它没有被重新调用,它只是还没有被触发。