【问题标题】:How can I make my setTimeouts get stopped here?我怎样才能让我的 setTimeouts 在这里停止?
【发布时间】:2016-03-31 04:46:52
【问题描述】:

我想要实现的行为是这样的:

在悬停/鼠标输入时,将背景图像从占位符更改为位置变化的 gif,以实现动画效果,然后在鼠标离开时返回占位符。

我的代码是

    $('.filmstrip').mouseenter(function(){
        var $that = $(this),
               w = $that.width(),
              fr = $that.attr('data-framerate');
        $that.css('background-image','url('+$that.attr('data-gifurl')+')');
        for ( var i = 1, n = $that.attr('data-ticks'); i <= n; ++i )
        {
            (function(j){
               setTimeout(function(){
                  $that.css('background-position-x','-'+(w*j)+'px');
               }, j*fr);
            })(i);
        }
        $that.bind('mouseleave',function(){
            $that.css('background-image','url('+$that.attr('data-placeholder')+')').css('background-position-x','0');
        });
    }); 

我遇到的错误是,如果 gif 还没有完成动画,那么

.css('background-position-x','0')

部分

$that.css('background-image','url('+$that.attr('data-placeholder')+')').css('background-position-x','0');
            });

不起作用,因为背景位置仍在被动画移动。所以我需要一些方法来首先停止setTimeout 的东西,如果它没有完成运行。知道我该怎么做吗?

【问题讨论】:

    标签: javascript jquery html


    【解决方案1】:

    这可能是用 CSS 而不是 javascript 做得更好。

    选项 #1 - 使用实际的 GIF

    你可以将你想要动画的帧编译成一个实际的 GIF 文件,然后根据悬停来改变背景图像:

    <div class="filmstrip"></div>
    

    然后是 CSS

    .filmstrip { background:transparent url('static_image.jpg') no-repeat 0 0 }
    .filmstrip:hover { background-image:url( 'animated_image.gif' ) }
    

    选项 #2 - 使用 CSS3 动画

    您可以将动画图像保留为一条帧(已知长度),然后使用类似的东西:

    <div class="filmstrip"></div>
    

    使用 CSS

    .filmstrip { background:transparent url('static_image.jpg') no-repeat 0 0 }
    @keyframes animate-bg {  
        0% { background-position: 0 0 }
      100% { background-position: -1000px 0 }
      /* where 1000px is the length of the strip */
    }
    .filmstrip:hover { animation: animate-bg 5s steps(50) infinite }
    /* where 5s is the overall loop length time and 50 is the number of frames in the strip */
    

    选项 #3 - 使用 Spritely

    Spritely 是一个 jQuery 插件,它似乎可以管理将幻灯片/精灵图像转换为动画的所有元素,包括能够启动/停止动画、重置到第一帧、更改 FPS 等。

    【讨论】:

      【解决方案2】:

      添加停止变量:

      $('.filmstrip').mouseenter(function(){
          var isStopped = false;
          var $that = $(this),
                 w = $that.width(),
                fr = $that.attr('data-framerate');
          $that.css('background-image','url('+$that.attr('data-gifurl')+')');
          for ( var i = 1, n = $that.attr('data-ticks'); i <= n && !isStopped; ++i )
          {
              (function(j){
                 setTimeout(function(){
                    if (!isStopped) {
                        $that.css('background-position-x','-'+(w*j)+'px');
                    }
                 }, j*fr);
              })(i);
          }
          $that.bind('mouseleave',function(){
              isStopped = true;
              $that.css('background-image','url('+$that.attr('data-placeholder')+')').css('background-position-x','0');
          });
      });
      

      如果 isStopped 在超时后不可访问(因为未测试),则只需在您影响 isStopped 值的内部范围内创建一个新变量。

      【讨论】:

        【解决方案3】:

        您可以使用基于区间的解决方案,例如

        $('.filmstrip').mouseenter(function() {
          var $that = $(this),
            w = $that.width(),
            fr = +$that.attr('data-framerate'),
            ticks = +$that.attr('data-ticks');
          $that.css('background-image', 'url(' + $that.attr('data-gifurl') + ')');
        
          var counter = 0;
          var interval = setInterval(function() {
            $that.css('background-position-x', '-' + (w * ++counter) + 'px');
            if (counter >= ticks) {
              clearInterval(interval);
            }
          }, fr);
          $(this).data('bg-interval', interval)
        }).mouseleave(function() {
          clearInterval($(this).data('bg-interval'));
          $(this).css('background-image', 'url(' + $(this).attr('data-placeholder') + ')').css('background-position-x', '0');
        });
        .filmstrip {
          height: 64px;
          border: 1px solid grey;
          background-position: right;
          background-position-y: inherit;
          display: inline-block;
          width: 64px;
        }
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
        <div class="filmstrip" data-framerate="400" data-ticks="10" data-gifurl="//cdn.sstatic.net/Sites/*/img/sprites.svg?v=bc7c2f3904bf">
        </div>

        【讨论】:

          【解决方案4】:

          你可以使用clearTimeout来停止setTimeOut

          工作演示-

          var myVar;
          
          function myFunction() {
              myVar = setTimeout(function(){ alert("Hello"); }, 3000);
          }
          
          function myStopFunction() {
              clearTimeout(myVar);
          }
          <p>Click the first button to alert "Hello" after waiting 3 seconds.</p>
          <p>Click the second button to prevent the first function to execute. (You must click it before the 3 seconds are up.)</p>
          
          <button onclick="myFunction()">Try it</button>
          <button onclick="myStopFunction()">Stop the alert</button>

          更多-

          Mozilla Developer Network

          W3School

          【讨论】: