在重新运行函数之前删除事件侦听器

Removing Event Listeners on before the function is re-run

提问人:ESDEE 提问时间:11/8/2023 更新时间:11/11/2023 访问量:27

问:

我想为飞镖创建一个记分板。 在这个游戏中,许多玩家轮流投掷 3 个飞镖。每个飞镖都会获得一定的分数。 我创建了与飞镖板上投掷的实际目标相对应的按钮。 此类按钮的示例: 玩家投掷 1,因此单击此按钮:1。

我的问题是将按钮上的事件侦听器与回合结束时自动切换到下一个玩家相结合。

通过下面的代码,似乎按钮点击仍然与前一个玩家相关联,因此当第二个玩家投掷时,这些投掷也计入第一个玩家......

所以在第一轮之后(每个玩家都投掷了 3 次,所以点击了 12 次按钮,player1 的 totalArrows = 21,这显然是错误的,这应该是 3。

我试图从事件侦听器中提取handleClick函数,但后来我似乎无法将按钮作为参数传递,这是分数所必需的。

我的代码:

// Player
//  remaining = how much of the score remains after each throw.
//  totalArrows = how many arrows has player thrown.
let player1 = { name: 'Steven', remaining: 501, totalArrows: 0};
let player2 = { name: 'Tom', remaining: 501, totalArrows: 0};
let player3 = { name: 'Nico', remaining: 501, totalArrows: 0};
let players = [player1, player2, player3];

// The buttons that can be clicked for scoring
const targetButtons = document.querySelectorAll(".target");

let playersIndex = 0;
let throws = 0;

function playerTurn() {
    let currentPlayer = players[playersIndex];
        
    targetButtons.forEach((button) => {
    
        button.addEventListener('click', function handleClick() {
        
            if (throws < 3 ) {
                currentPlayer.totalArrows++;
                const scoreThisThrow = parseInt(this.textContent);
                currentPlayer.remaining -= scoreThisThrow:
                throws++;
                
                if (throws === 3) {
                    button.removeEventListener("click", handleClick);
                    playersIndex = (playersIndex + 1) % players.length;
                    throws = 0;
                    playerTurn()
                }
            }
        });
    });
}

// Start the game
playerTurn()
JavaScript 数组函数 addEventListener

评论


答:

0赞 BobRodes 11/8/2023 #1

你的逻辑是关闭的。正如你所拥有的,你只评估当.当然,这永远不会发生:如果小于 3,则永远不能等于 3。因此,请将您从另一个街区中取出。players === 3players < 3playersplayersif players === 3if

这应该可以解决您的问题,而不必删除事件侦听器。我也没有看到你对你的财产做了什么。我假设它的使用超出了您在此处定义的问题的范围。但是,如果你使用它只是为了试图弄清楚为什么只有一个球员得到了所有的投掷,那么你可以安全地删除它。totalArrows

顺便说一句,如果你不是专门从你的设置外部调用,你不需要给它一个名字:等等。handleClickaddEventListenerbutton.addEventListener('click', function(e) {

请注意,通常还会向函数添加参数,通常是 或 。这提供了对元素实现的对象的引用。因此,例如,如果要防止事件的正常行为,可以将 .执行此操作的一个常见示例是,窗体中有一个类型的按钮,并且想要重写该按钮的默认行为。eeventEventbuttone.preventDefaultsubmit

评论

0赞 ESDEE 11/8/2023
totalArrows 确实超出了范围。我把它留在那里进行故障排除。需要明确的是,所有玩家都会得到投掷,但之前的玩家也会在回合后得到投掷。我已经更改了代码,但问题仍然存在。此外,在 if 语句中,我在 throw 中添加了 1,因此之后 throws 可以是 3,第二个 if 语句将是真的?
0赞 ESDEE 11/8/2023
我已经更改了代码,但问题仍然存在。button.addEventListener('click', function (e) { e.preventDefault(); if (throws < 3) { ... } if (throws === 3) { playersIndex = (playersIndex + 1) % players.length; throws = 0; playerTurn() }
0赞 BobRodes 11/9/2023
@ESDEE 首先,我认为你不需要使用 .我只是用它来说明对象的用法。接下来,你是在告诉我,在将另一个块移出后,你得到了与以前完全相同的行为?这听起来很不对劲。也许您可以发布修改后的代码?preventDefaultEventif (throws === 3)if
0赞 ESDEE 11/11/2023 #2

我已经设法让它工作了。代码绝对需要优化/清理,但游戏在三次投掷后自动进入下一个玩家,没有任何箭头或剩余点问题。

我加入了飞镖 X01 游戏中通常使用的计分系统:

  • 当赢得一定数量的盘数时,就赢得了一场比赛。
  • 当赢得一定数量的腿时,就赢了一盘。
  • 当玩家达到 0 或更低时,将赢得一回合。

代码如下:

// remaining = how much of the score remains after each throw.
// totalArrows = how many arrows has player thrown.
// legs = number of legs won.
// sets = number of sets won.
const player1 = { name: 'Steven', remaining: 501, totalArrows: 0, legs: 0, sets: 0};
const player2 = { name: 'Tom', remaining: 501, totalArrows: 0, legs: 0, sets: 0};
const player3 = { name: 'Nico', remaining: 501, totalArrows: 0, legs: 0, sets: 0};
const players = [player1, player2, player3];

// The buttons that can be clicked for scoring
const targetButtons = document.querySelectorAll(".target");
const numPlayers = players.length;
const totalLegs = 3;
const totalSets = 3;
let playersIndex = 0;
let currentPlayer = players[playersIndex];
let throws = 0;
let gameFinished = false

function playerTurn() {
                
    targetButtons.forEach((button) => {
    
        button.addEventListener('click', function handleClick() {
        
            if (throws < 3 ) {
                currentPlayer.totalArrows += 1;
                const scoreThisThrow = parseInt(this.textContent);
                currentPlayer.remaining -= scoreThisThrow:
                throws++;
                
                if (throws === 3 || currentPlayer.remaining < 1) {
                    // TODO: Bust rule
                    // TODO: Double out
                    if (currentPlayer.remaining < 1) {    // Player wins leg
                        currentPlayer.legs += 1;
                        if (currentPlayer.legs === totalLegs) {    // Player wins set
                            currentPlayer.sets += 1;
                            // Reset leg count
                            players.forEach((player) => {
                                player.legs = 0
                            });
                            if (player.sets === totalSets) {    // Player wins the game
                                gameFinished = true;
                            } else {
                                playersIndex = (playersIndex + 1) % numPlayers;
                                currentPlayer = players[playersIndex];
                                throws = 0;
                                return;
                            }
                        }
                        playersIndex = (playersIndex + 1) % numPlayers;
                        currentPlayer = players[playersIndex];
                        throws = 0;
                        return;
                    }
                    if (throws === 3) {
                        playersIndex = (playersIndex + 1) % players.length;
                        currentPlayer = players[playersIndex];
                        throws = 0;
                        return;
                    }
                    if (!gameFinished) {
                        playerTurn();
                    }
                }
            }
        });
    });
}
    
playerTurn()