为什么removeEventListener不起作用?

Jaw*_*ser 1 javascript event-listener event-handling

我不确定这里有什么问题,但是在chrome和firefox中测试,我发现我在javascript中从一个元素中删除一个EventListener时做错了.

上下文是一个画布游戏.首先,会显示一个启动画面,您可以单击该界面开始游戏.点击开始后,我想删除监听器.

主要的兴趣点是startGame函数中的removeEventListener.它不会引发错误.代码执行(我在控制台中看到游戏启动消息,我可以看到"这个"是游戏实例).我完全很困惑为什么如果我继续点击画布每次运行startGame.预期的行为是,一旦删除了EventListener,单击那里就不会执行任何操作.

救命!

function Game(canvas) {
  this.c = canvas;
  this.ctx = this.c.getContext("2d");
  this.c.width = CANVAS_WIDTH;
  this.c.height = CANVAS_HEIGHT;

  // Background image
  this.bgReady = false;
  this.bgImage = new Image();
  this.bgImage.onload = function () {
    window.g.bgReady = true;
  };
  this.bgImage.src = MAIN_BACKGROUND;
}


Game.prototype.setSplash = function() {
  if (this.bgReady) {
    this.ctx.drawImage(window.g.bgImage, 0, 0);
    this.ctx.font="48px Helvetica";
    this.ctx.textAlign = "center";
    this.ctx.fillStyle="rgb(0,0,255)";
    this.ctx.fillText("Click To Start",310,240);
    document.getElementById("cnvs").addEventListener(
      'click',this.startGame.bind(this),true);
  } else {
    // since setSplash is an early function
    // wait a bit for the background image and then try again
    setTimeout(this.setSplash.bind(this),100);
    console.log("bgImage not ready...");
  }
}

Game.prototype.startGame = function() {
  console.log("game starting ...");
  console.log(this);

  // step 1, remove the click listener for this function

  // why isn't this working?!
  document.getElementById("cnvs").removeEventListener(
    'click',this.startGame,true);
}
...
// other stuff ...
function initialize() {
  // Get the canvas
  var c = document.getElementById("cnvs");

  // Create a game object
  window.g = new Game(c);

  // Set the splash page
  g.setSplash();
}
window.onload=initialize;
Run Code Online (Sandbox Code Playgroud)

更多信息:

我还有一个版本,其中非工作删除被写为:

this.c.removeEventListener('click',this.startGame,true);
Run Code Online (Sandbox Code Playgroud)

与上面引用的代码相同的行为.


编辑:回复mczepiel的第一个答案

我正试图像这样实现你的答案:

Typer.prototype.setSplash = function() {
  if (this.bgReady) {
    this.ctx.drawImage(window.t.bgImage, 0, 0);
    this.ctx.font="48px Helvetica";
    this.ctx.textAlign = "center";
    this.ctx.fillStyle="rgb(0,0,255)";
    this.ctx.fillText("Click To Start",310,240);
    var boundFunction = this.startGame.bind(this);
    document.getElementById("cnvs").addEventListener(
      'click',boundFunction,true,boundFunction);
  } else {
    // since setSplash is an early function 
    // wait a bit for the background image and then try again 
    setTimeout(this.setSplash.bind(this),100);
    console.log("bgImage not ready...");
  }
}

Typer.prototype.startGame = function(boundFunction) {
  console.log("game starting ...");
  console.log(this);  // strangely, now this is an Object rather 
                      // than Game, it still has the properties of 
                      // Game tho

  // step 1, remove the click listener for this function

  // still isn't working... 
  document.getElementById("cnvs").removeEventListener(
    'click',boundFunction,true);
}
Run Code Online (Sandbox Code Playgroud)

我想我理解你的建议,但也许不是.上面的代码仍然不会删除侦听器.任何帮助赞赏.

mcz*_*iel 5

您需要存储对调用结果的引用this.startGame.bind(this),并将相同的值传递给两者addEventListenerremoveEventListener

remove调用期望删除作为侦听器添加的完全相同的对象.

如果你想在各种风格中看到相同的问题,那么removeEventListener的可能重复不起作用.

编辑未经测试的袖口建议:

Typer.prototype.setSplash = function() {
  if (this.bgReady) {
    // draw stuff

    var canvasElement = document.getElementById("cnvs");
    var dismissSplash = function (evt) {
        canvasElement.removeEventListener('click', dismissSplash, true);
        this.startGame();
    }.bind(this);

    canvasElement.addEventListener('click', dismissSplash, true);
  } else {
        // try to show splash later
    }
}

Typer.prototype.startGame = function() {
    // start game
}
Run Code Online (Sandbox Code Playgroud)