在requestAnimationFrame中传递class的方法

时间:2017-07-07 15:35:42

标签: javascript

当我在控制台中调用app.update()时,这有效,但当我使用requestAnimationFrame时出现错误:

  

未捕获的TypeError:无法读取属性' drop'更新时未定义的内容(oee.html:40)

使用setInterval时可以正常工作。

我错过了什么?

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title></title>
    <style media="screen">
      *{
        margin:0;
        padding:0;
      }
      #app{
        height:100vh;
        width:100vw;
        background-color: red;
        overflow: hidden;
      }
      .drop{
        position:absolute;
        background-color:#fff;
        top:10px;
        width: 5px;
      }
    </style>
  </head>
  <body>
    <div id="app">
    </div>
    <script type="text/javascript">
      class App{
        constructor(){
          this.el = document.getElementById("app");
          this.height=this.el.clientHeight;
          this.width=this.el.clientWidth;
          this.drops=[];
          for(var i=0;i<100;i++){
            this.drops.push(new Drop(this.height,this.width));
          }
        }
        update(){
          this.drops.forEach(function(drop){
            drop.update();
          });
        }
      }

      class Drop{
        constructor(appHeight,appWidth){
          this.speed=Math.random();
          this.el=document.createElement("div");
          this.el.setAttribute("class","drop");
          this.el.style.height=(Math.random()*10+5)+"px";
          this.el.style.left=(Math.random()*appWidth)+"px";
          this.appHeight=appHeight;
          document.getElementById("app").appendChild(this.el);
          this.el.style.top=0;
        }

        update(){
          this.top=this.el.style.top.replace("px","");
          this.el.style.top=(this.top>this.appHeight)?"0px":(parseFloat(this.top) + parseFloat(this.speed*300))+"px";
        }
      }
      var app=new App();
      requestAnimationFrame(app.update);
    </script>
  </body>
</html>

1 个答案:

答案 0 :(得分:1)

当您致电app.update()时,您正在调用update函数作为app对象的方法。

但问题中显示的代码并未将您的函数称为方法:

requestAnimationFrame(app.update);

当您编写app.update(不使用括号)时,您只是将app.update函数作为独立函数引用。它失去了与app对象的连接。当requestAnimationFrame()稍后调用您的update函数时,它只会在没有任何this对象的情况下直接调用该函数。因此,当update引用this.drops时,它会失败。

您没有列出您的setInterval()版本,但我们可以确定的一件事是看起来像这样:

setInterval( app.update, 10 );

如果这是您使用的代码,则会遇到与requestAnimationFrame()相同的问题。你可能写过类似的东西:

setInterval( function() {
    app.update();
}, 10 );

现在,您的setInterval()回调是匿名函数,该函数将app.update() 称为方法

您可以使用requestAnimationFrame()执行相同的操作,但每次要等待另一帧时都需要调用requestAnimationFrame()。换句话说,它更像setTimeout()而不是setInterval()。所以它看起来像这样:

var updater = function() {
    app.update();
    requestAnimationFrame( updater );  // for subsequent frames
};

requestAnimationFrame( updater );  // for the first frame

现在您的代码应该按预期工作。

这是一个updated version of yuriy636's CodePen test动画制作工作。