web-dev-qa-db-fra.com

requestAnimationFrame avec ce mot clé

J'utilise webkitRequestAnimationFrame mais je ne parviens pas à l'utiliser à l'intérieur d'un objet. Si je passe le mot clé this, il utilisera window et je ne trouverai pas le moyen de l'utiliser à la place.

Exemple:

Display.prototype.draw = function(){
  this.cxt.clearRect(0, 0, this.canvas.width, this.canvas.height);
  //Animation stuff here.

  window.webkitRequestAnimationFrame(this.draw);
};

J'ai aussi essayé cela mais en vain:

Display.prototype.draw = function(){
  this.cxt.clearRect(0, 0, this.canvas.width, this.canvas.height);
  //Animation stuff here.

  var draw = this.draw;
  window.webkitRequestAnimationFrame(draw);
};
39
Ryan

J'essaie de passer à display.draw, qui est la fonction dans laquelle réside webkitRequestAnimationFram.

webkitRequestAnimationFrame appellera probablement la fonction que vous transmettez, quelque chose comme ceci:

function webkitRequestAnimationFrame(callback)
{
    // stuff...
    callback();
    // other stuff...
}

À ce stade, vous avez dissocié (détaché) la fonction draw de son contexte d’appel. Vous devez lier la fonction (draw) à son contexte (l'instance de Display).

Vous pouvez utiliser Function.bind , mais nécessite le support de JavaScript 1.8 (ou utilisez simplement le correctif recommandé).

Display.prototype.draw = function()
{
    // snip...

    window.webkitRequestAnimationFrame(this.draw.bind(this));
};
74
Matt Ball

Maintenant que ES6/2015 est arrivé, si vous utilisez un transpiler, une fonction de flèche possède une liaison lexicale this de sorte que

window.webkitRequestAnimationFrame(this.draw.bind(this));

tu peux faire:

window.webkitRequestAnimationFrame(() => this.draw());

ce qui est un peu plus propre.

Je l'ai utilisé efficacement avec TypeScript transpiling to ES5.

16
James World

Je ne peux pas garantir que c'est une bonne idée et que j'ai raison, mais exécuter .bind sur chaque requestAnimationFrame signifie créer une nouvelle fonction à chaque itération. Cela ne me semble pas juste.

C'est pourquoi, dans mon projet, j'ai mis en cache la fonction liée pour éviter l'anti-motif. 

Exemple simple:

var Game = function () {
    this.counter = 0;
    this.loop = function () {
        console.log(this.counter++); 
        requestAnimationFrame(this.loop);
    }.bind(this);
    this.loop();
}
var gameOne = new Game();

Si vous avez un projet plus complexe avec un héritage prototype, vous pouvez toujours créer une fonction en cache avec "this" lié dans le constructeur de l'objet.

var Game = function () {
    this.counter = 0;
    this.loopBound = this.loop.bind(this);
    this.loopBound();
}
Game.prototype.loop = function () {
    console.log(this.counter++); 
    requestAnimationFrame(this.loopBound);
}
var gameOne = new Game();

Pensées? http://jsfiddle.net/3t9pboe8/ (regardez dans la console)

5
Pawel

que dis-tu de ça:

Display.prototype.draw = function(){
  this.cxt.clearRect(0, 0, this.canvas.width, this.canvas.height);
  //Animation stuff here.

  window.webkitRequestAnimationFrame( $.proxy(function() {this.draw()}, this) );
};

... en supposant que vous utilisez jQuery

3
bogdan

vous ne devez pas utiliser "this" . Restez simple.

var game = {
      canvas:null,
      context:null,

    init:function(){
            // init canvas, context, etc
    },      

    update:function(){
        //do something
        game.render();                        
        requestAnimationFrame(game.update, game.canvas);        
    },            
};
0
Tomáš

Outre la méthode bind et la solution de fonction de flèche (proposée par la réponse de Jamaes World), un autre travail (plutôt ancien) pourrait être:

var self = this
window.webkitRequestAnimationFrame(
    function() {
        self.draw()
    }
);
0
MortezaE