为什么在jQuery中传递给我的回调函数的参数会不断变化?

时间:2012-05-09 18:50:14

标签: javascript closures jquery jquery-callback

我正在研究解决jQuery中着名的有争议删除"requestAnimationFrame"的不同方法,其中animate被还原为使用setTimeout / setInterval而不是即将到来的requestAnimationFrame API。这当然会导致一些已知的问题,即当该页面的浏览器选项卡不在焦点时,动画会排队等候(因为我希望当页面的选项卡失焦时动画效果暂停,这就成了问题)。一种解决方案是将所有内容包装在真实“requestAnimationFrame”的跨浏览器requestAnimFrame shim中,另一种解决方案是为动画元素生成唯一ID以及时间戳,并仅在窗口聚焦时运行动画。

这是一个快速而又肮脏的演示,解释了我在第二种焦点监听器和ID传递方法中遇到的令人沮丧的问题: http://jsfiddle.net/bcmoney/NMgsc/17

更新(主要问题已解决):http://jsfiddle.net/bcmoney/NMgsc/

准系统代码:

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>window.focus listener EXAMPLE - jsFiddle demo by bcmoney</title> 
<script type='text/javascript' src='https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js'></script>
<style type='text/css'>
  body { overflow:hidden; }
  #container { width:100%; height:100%; }
  #animated { width:120px; position:absolute; left:2px; top:20px; padding:50px; background:skyblue; color:white }
</style>
<script type='text/javascript'>//<![CDATA[ 
$(function(){
  var animation = 1;
  var startTime = undefined;
  var FPS = 60; //frames per second
  var AVAILABLE_WIDTH = $("#container").width() || "800px";
  var animation = null;
  var FOCUSED = false;
  var timestamp = new Date().getTime();
  var PAGE_ID = $("body").attr("id") + "-animated-"+timestamp;

  function continueScrolling(p) {
      console.log('FUNCTION p: '+p);
      if (FOCUSED === true && p === PAGE_ID) {
        animation = setTimeout(scrollRight.bind(p), FPS);
      } else {
          clearTimeout(animation);
          $('#animated').stop(true, true);
      }
  }

  var scrollRight = function(p) {
      time =  +new Date;
      startTime = (startTime !== undefined) ? startTime : time-FPS;
    move = ((time - startTime)/10 % AVAILABLE_WIDTH)+"px";
      console.log('P:'+p+' | T:'+time+' | ST:'+startTime+' | W:'+AVAILABLE_WIDTH+'\n'+move);
    $('#animated').animate({
         "left":move
      }, 
      1000/FPS, 
      "linear",
       function() {
         console.log('CALLBACK p: '+p);         
         continueScrolling(p);
       }
    );
  }  

  $(window).blur(function(){
     FOCUSED = false;
    $('#stop').click();
  });

  $(window).focus(function(){
     FOCUSED = true;
    $('#start').click();   
  });

  $('#start').click(function() {  
    scrollRight(PAGE_ID);
  });

  $('#stop').click(function() {
    $('#animated').stop(true, true);
    clearTimeout(animation);
  });
});//]]>  
</script>
</head>
<body id="slider">
  <a id="start" href="#start">Start</a> | <a id="stop" href="#stop">Stop</a>
<div id="container">
    <div id="animated">Animated content</div>
</div>
</body>
</html>

我最近才意识到可能不需要唯一的ID,并且使用焦点听众抛弃我对它们的初步调查,支持shim approach for now;然而,这个修补程序指出了jQuery的另一个潜在问题(或者更可能是我的理解),将参数传递给jQuery中的回调函数,并确保参数的值通过动画的上下文传播。

如您所见,动画启动和停止,因为不再传递值“p”。我不是关闭闭包的专家,但是我看到他们提出here作为一个解决方案以及使用 $ .proxy (我在here尝试之前休息并发布沮丧地去。即使在链接API调用时,我也从来没有遇到 $。ajax $。getJSON 回调这个问题,但由于某些原因我似乎无法获得回调参数,以便为后续调用 continueScrolling 函数保持其值。一些JS / jQuery忍者的任何帮助将不胜感激......

1 个答案:

答案 0 :(得分:2)

setTimeout需要第一个参数的函数:

        animation = setTimeout(function(){scrollRight(p)}, FPS);

http://jsfiddle.net/K2nfM/