RemoveEventListener 不删除事件
RemoveEventListener not removing event
下面的代码应该为轮到玩家手中的每张纸牌添加事件侦听器,然后在轮到其他玩家时删除事件。
它不工作。一旦事件最初设置在他们的第一回合,该玩家的卡片仍然可以点击。
takeTurn ( playerIndex ) {
console.log(this.name);
let handCards = document.getElementById(this.name).querySelector('.handCards');
let theCards = handCards.querySelectorAll('.handCards .card');
let that = this;
for ( let h = 0; h < theCards.length; h++ ) {
theCards[h].addEventListener("click", function onPlayCard (){
let theseCards = handCards.querySelectorAll('.handCards .card');
let discarded = that.playCard(theCards[h], theseCards, handCards);
that.gameInstance.discardPile.push(discarded);
console.log(that.gameInstance.discardPile);
for ( let e = 0; e < theseCards.length; e++) {
theseCards[e].removeEventListener("click", onPlayCard, false);
}
console.log(that.name + 'is done');
that.gameInstance.nextPlayer( playerIndex );
}, false);
}
}
我尝试了 here and here 中的一些想法,但其中 none 完全解决了问题。
感谢任何帮助。我可能很快就会拔掉头发。我以为我知道这些东西。
问题:
问题是您要为每张卡片添加一个唯一的函数实例,然后尝试仅使用所点击卡片的函数实例将它们全部删除。这只会删除与添加到单击卡片的实例实际匹配的一张卡片。
因此元素 0 获得处理程序 0,元素 1 获得处理程序 1,元素 2 获得处理程序 2,依此类推...
当一个元素被点击时,比如元素 2,然后您迭代所有元素以删除它们的处理程序,但是您为被点击的元素 2 提供处理程序。处理程序 2 仅对删除元素 2,而不是其他元素。
解决方法:
根据您当前的代码,我实际上不会给出解决方案,只是说这将涉及维护一个处理程序数组,这些处理程序与它们所绑定的元素并行。它会工作得很好,但我认为重新设计应用程序可能会更好。
另一种方法:
IMO,重复绑定和解除绑定表明在设计您的应用程序时需要采用不同的方法。
您可以采用面向对象的方法,将应用中的每种类型的项目表示为 "class" (构造函数)。因此,您需要 Game
管理整个游戏,Card
代表纸牌的每个实例,Player
代表每个玩家。
为每张卡片创建一个 Card
实例。也许其他特殊的,如 Dealer
或 Deck
和 Discard
用于弃牌堆。 Card
可以具有表示其值和花色的属性,以及引用该卡的当前持有者的 .owner
属性。例如,.owner
可以是 Player
、Discard
堆或 Deck
。
Game
引用了所有这些对象,因此它可以协调它们。它通过将 .owner
从 Deck
更改为某个 Player
来发牌。当 Player
弃掉 Card
时,卡片的 .owner
变为 Discard
。
所以基本上每个对象都维护自己的"state"。
每个项目还可以引用其 DOM 元素,您可以将处理程序绑定到该元素。处理程序将通过 this
引用 DOM 元素,但它还需要引用其关联实体的数据。大多数人会为每个对象创建一个单独的处理程序,并使用闭包来引用数据。我个人会使用一个鲜为人知但 非常 有用的功能,称为 EventListener 接口 。我会留给你研究这个话题。
具体如何设置取决于您。 Game
是否应该将 .owner
分配给 Card
?还是Dealer
?还是应该将 Card
传递给所有者 (如 Player
) 并让其分配 .owner
属性?或者 Card
应该有一个方法来接收它的新所有者并将它分配给它自己的 .owner
属性?由你决定。
希望这能给你一些想法。
下面的代码应该为轮到玩家手中的每张纸牌添加事件侦听器,然后在轮到其他玩家时删除事件。
它不工作。一旦事件最初设置在他们的第一回合,该玩家的卡片仍然可以点击。
takeTurn ( playerIndex ) {
console.log(this.name);
let handCards = document.getElementById(this.name).querySelector('.handCards');
let theCards = handCards.querySelectorAll('.handCards .card');
let that = this;
for ( let h = 0; h < theCards.length; h++ ) {
theCards[h].addEventListener("click", function onPlayCard (){
let theseCards = handCards.querySelectorAll('.handCards .card');
let discarded = that.playCard(theCards[h], theseCards, handCards);
that.gameInstance.discardPile.push(discarded);
console.log(that.gameInstance.discardPile);
for ( let e = 0; e < theseCards.length; e++) {
theseCards[e].removeEventListener("click", onPlayCard, false);
}
console.log(that.name + 'is done');
that.gameInstance.nextPlayer( playerIndex );
}, false);
}
}
我尝试了 here and here 中的一些想法,但其中 none 完全解决了问题。
感谢任何帮助。我可能很快就会拔掉头发。我以为我知道这些东西。
问题:
问题是您要为每张卡片添加一个唯一的函数实例,然后尝试仅使用所点击卡片的函数实例将它们全部删除。这只会删除与添加到单击卡片的实例实际匹配的一张卡片。
因此元素 0 获得处理程序 0,元素 1 获得处理程序 1,元素 2 获得处理程序 2,依此类推...
当一个元素被点击时,比如元素 2,然后您迭代所有元素以删除它们的处理程序,但是您为被点击的元素 2 提供处理程序。处理程序 2 仅对删除元素 2,而不是其他元素。
解决方法:
根据您当前的代码,我实际上不会给出解决方案,只是说这将涉及维护一个处理程序数组,这些处理程序与它们所绑定的元素并行。它会工作得很好,但我认为重新设计应用程序可能会更好。
另一种方法:
IMO,重复绑定和解除绑定表明在设计您的应用程序时需要采用不同的方法。
您可以采用面向对象的方法,将应用中的每种类型的项目表示为 "class" (构造函数)。因此,您需要 Game
管理整个游戏,Card
代表纸牌的每个实例,Player
代表每个玩家。
为每张卡片创建一个 Card
实例。也许其他特殊的,如 Dealer
或 Deck
和 Discard
用于弃牌堆。 Card
可以具有表示其值和花色的属性,以及引用该卡的当前持有者的 .owner
属性。例如,.owner
可以是 Player
、Discard
堆或 Deck
。
Game
引用了所有这些对象,因此它可以协调它们。它通过将 .owner
从 Deck
更改为某个 Player
来发牌。当 Player
弃掉 Card
时,卡片的 .owner
变为 Discard
。
所以基本上每个对象都维护自己的"state"。
每个项目还可以引用其 DOM 元素,您可以将处理程序绑定到该元素。处理程序将通过 this
引用 DOM 元素,但它还需要引用其关联实体的数据。大多数人会为每个对象创建一个单独的处理程序,并使用闭包来引用数据。我个人会使用一个鲜为人知但 非常 有用的功能,称为 EventListener 接口 。我会留给你研究这个话题。
具体如何设置取决于您。 Game
是否应该将 .owner
分配给 Card
?还是Dealer
?还是应该将 Card
传递给所有者 (如 Player
) 并让其分配 .owner
属性?或者 Card
应该有一个方法来接收它的新所有者并将它分配给它自己的 .owner
属性?由你决定。
希望这能给你一些想法。