animate() 在滚动停止之前不会触发

Posted

技术标签:

【中文标题】animate() 在滚动停止之前不会触发【英文标题】:animate() not firing until scrolling stops 【发布时间】:2015-11-26 23:39:35 【问题描述】:

目标:

我希望我的固定标题元素在用户向下滚动时从屏幕上滑出(有效地隐藏),并在用户向上滚动时向下移动。

问题:

实际的动画和逻辑工作正常,但动画直到用户停止滚动才开始,而不是在滚动仍在正常进行时开始。

这在 Chrome 和 Firefox 上被复制。但是,使用完全相同的代码,该解决方案似乎可以在 JSFiddle 中正常工作:

https://jsfiddle.net/8cj7v6n5/

javascript

var lastScroll = 0;
var scrollDelta = 10;
var animating = false;

$(window).on('scroll', function() 
    //if animation isn't currently taking place, begin animation
    if (!animating) hasScrolled();
);

function hasScrolled() 
    var st = $(window).scrollTop();

    //if user hasn't scrolled past scrollDelta, do not animate yet
    if(Math.abs(lastScroll - st) <= scrollDelta)
        return;

    animating = true;

    if (st > lastScroll && st >= 0)    // Scroll Down
        $('header').animate(  top: -80 ,  queue: false, duration: 500, complete: function()  animating = false;  );
    
    else   // Scroll Up
        $('header').animate(  top: 0 ,  queue: false, duration: 500, complete: function()  animating = false  );
    
    lastScroll = st;

【问题讨论】:

为什么不用 CSS 而不是 javascript? @JackAllan 我尝试在 CSS 中使用 transition 属性,但没有成功。是这个意思吗? 我的意思是,与其为标题设置动画,不如使用 CSS 将其粘贴到视口的顶部...当然假设那是您想要实现的目标 @JackAllan 使用 CSS 修复;那不是问题。对不起,如果我解释得不够好。我想在用户向下滚动时将其滑出屏幕,然后在用户向上滚动时将其滑回其原始位置。想想当您在移动浏览器上滚动时隐藏的地址栏。 【参考方案1】:

您可以不使用动画标志,而是将动画排队并使用 stop() 和 animate() 来运行队列中的最后一个动画。

编辑:您可以使用方向标志来检测滚动方向是否发生变化。

JavaScript:

var lastScroll = 0;
var scrollDelta = 10;
var animationDirection = 0; // 0 for up direction, 1 for down direction

$(window).on('scroll', function () 
    hasScrolled();
);

function hasScrolled() 
    var st = $(window).scrollTop();
    if (Math.abs(lastScroll - st) <= scrollDelta)
        return;

    if (st > lastScroll && st >= 0 && animationDirection == 0)     // Scroll Down                                    
        $('header').stop().animate( top: -80 , 500);
        animationDirection = 1;
    
    else if (st <= lastScroll && st >= 0 && animationDirection == 1)   // Scroll Up
        animationDirection = 0;
        $('header').stop().animate( top: 0 , 500);
    
    lastScroll = st;

JSFiddle:https://jsfiddle.net/8cj7v6n5/27/

【讨论】:

感谢您的回答;但是,这并不理想,因为即使新动画在同一个方向上,它也会中途停止当前正在运行的动画。你的小提琴就是一个例子。 在这种情况下,您可以将标志用于动画方向。编辑了答案。 谢谢,好像很接近了!在我接受之前,在滚动开始之后,动画触发之前似乎仍然存在一个小的延迟(不是由于scrollDelta 数字)。你有什么想法吗?我知道这是一个模糊的问题...... 如果我登录控制台,它显示动画立即开始。你可能想玩弄动画的持续时间和easing effect 来修复明显的延迟。【参考方案2】:

问题是您用于 lastscroll 的值仅在动画发生时更新。它应该始终更新,因为您可以在动画运行时滚动屏幕,并且 lastscroll 值将与真正的顶部滚动值不同,然后您再次比较这些值并且系统认为它高于或低于它的实际值。

例子:

    窗口滚动顶部为 0 你向下滚动 -> 第一个动画 fires,此时的Window scrolltop为100,并分配给 可变圣。 你一直向下滚动 -> 标志开启,动画开启 不火,此时的Window scrolltop是200但不是 已分配。 第一个动画结束 -> st 分配给 lastscroll (100) 你向上滚动的下一个动作,lastscroll 是 100,真正的滚动顶部是 实际上是 200。新的滚动顶部是 190,但是当您与 lastscroll 进行比较时,系统认为您正在向下滚动。

这是更正后的代码:

var lastScroll = 0;
var scrollDelta = 10;
var animating = false;

$(window).on('scroll', function() 
    //if animation isn't currently taking place, begin animation
    if (!animating) hasScrolled()elselastScroll = $(window).scrollTop();;
);

function hasScrolled() 
    var st = $(window).scrollTop();

    //if user hasn't scrolled past scrollDelta, do not animate yet
    if(Math.abs(lastScroll - st) <= scrollDelta)
        return;

    animating = true;

    if (st > lastScroll && st >= 0)    // Scroll Down
        $('header').animate(  top: -80 ,  queue: false, duration: 500, complete: function()  animating = false;  );
    
    else   // Scroll Up
        $('header').animate(  top: 0 ,  queue: false, duration: 500, complete: function()  animating = false  );
    
    lastScroll = st;

这是我用来调试控制台日志的小提琴: https://jsfiddle.net/8cj7v6n5/18/

编辑: 这段代码在小提琴之外对我有用,如果它有效,请尝试它,那么问题出在页面的另一个组件中,没有在此处发布。 也许是另一行代码或库覆盖了 .animate() 或滚动事件的行为。

<html>
  <head>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
  <script type="text/javascript" charset="utf-8">
var lastScroll = 0;
var scrollDelta = 10;
var animating = false;

var lastScroll = 0;
var scrollDelta = 10;
var animating = false;

$(window).on('scroll', function() 
    //if animation isn't currently taking place, begin animation
    if (!animating) hasScrolled()elselastScroll = $(window).scrollTop();;
);

function hasScrolled() 
    var st = $(window).scrollTop();

    //if user hasn't scrolled past scrollDelta, do not animate yet
    if(Math.abs(lastScroll - st) <= scrollDelta)
        return;

    animating = true;

    if (st > lastScroll && st >= 0)    // Scroll Down
        $('header').animate(  top: -80 ,  queue: false, duration: 500, complete: function()  animating = false;  );
    
    else   // Scroll Up
        $('header').animate(  top: 0 ,  queue: false, duration: 500, complete: function()  animating = false  );
    
    lastScroll = st;

  </script>
  <style type="text/css">
  body 
    height: 2000px;
    width: 100%;
    background-image: url(http://static.tumblr.com/cc2l8yc/qa8nbkd68/2.jpg);
    background-repeat: repeat;
  

  header 
      height: 80px;
      width: 100%;
      background-color: red;
      position: fixed;
      top: 0;
      left: 0;
  
  </style>
  </head>
  <body>
    <header></header>
  </body>
</html>

【讨论】:

谢谢!这是完全有道理的,你的小提琴似乎工作正常,但是相同的代码产生了我最初得到的相同(错误)结果,在滚动停止之前动画不会触发,无论我滚动了多远.关于为什么我的窗口与小提琴窗口的行为不同的任何想法? 我无法重现该问题。检查答案的更新。

以上是关于animate() 在滚动停止之前不会触发的主要内容,如果未能解决你的问题,请参考以下文章

scroll滚动到一定距离触发事件/返回顶部animate

网页中滚动条可以触发animate动画效果么,就是边滚动条下滑,边出现其效果?

jQuery - .animate() 在滚动时非常延迟

仅在用户滚动时调用 Scroll,而不是在 animate()

jquery animate 不会触发

动画没有停止使用 UIView.animate