You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何将按钮点击事件放入函数后,我的Simon游戏JS代码出错?

Simon游戏按钮点击事件绑定问题排查与修复

你把按钮点击事件放到nextSequence里的做法会导致重复绑定事件处理器——每次调用nextSequence(比如每升一级),就会给所有.btn多绑一次点击回调。这意味着当用户点击按钮时,同一个逻辑会被执行多次:比如到Level 3时,按钮已经被绑定了3次点击事件,点击一次会往userClickedPattern里push3次相同颜色,直接导致checkAnswer判断出错,程序逻辑混乱。

另外,游戏结束后(gameStarted=false),之前绑定的所有点击事件依然存在,用户点击按钮还是会触发回调,这也不符合你“仅游戏开始后按钮才可点击”的需求。


方案一:绑定事件+状态判断(最简单)

保留点击事件的外部绑定,在回调开头加入gameStarted状态判断,只有游戏启动后才执行后续逻辑。这样既实现了“未开始时点击无效”的需求,又不会出现重复绑定的问题:

var buttonColours = ["red", "blue", "green", "yellow"];
var gamePattern = [];
var userClickedPattern = [];
var gameStarted = false;
var level = 0;

$(document).on("keydown", function (e){
    if (gameStarted===false) {
        gameStarted = true;
        level = 0; // 去掉原代码中的var,避免局部变量覆盖全局level
        $("#level-title").text("Level " + level);
        nextSequence();
    }
});

// 点击事件保留在外部,加入状态判断
$(".btn").on("click", function () {
    // 游戏未开始时直接返回,不执行任何逻辑
    if (!gameStarted) return;
    
    var userChosenColour = $(this).attr("id");
    userClickedPattern.push(userChosenColour);
    playSound(userChosenColour);
    animatePress(userChosenColour);
    checkAnswer(userClickedPattern.length - 1);
});

function nextSequence() {
    userClickedPattern = [];
    level++;
    $("#level-title").text("Level " + level);
    var randomNumber = Math.floor(Math.random() * 4);
    var randomChosenColour = buttonColours[randomNumber];
    gamePattern.push(randomChosenColour);
    $("#" + randomChosenColour).fadeOut(100).fadeIn(100).fadeOut(100).fadeIn(100);
    playSound(randomChosenColour);  
}

function playSound(name) {
    var playAudio = new Audio("./sounds/"+name+".mp3");
    playAudio.play(); 
}

function animatePress(currentColour) {
    $("#" + currentColour).addClass("pressed");
    setTimeout(function() {
        $("#" + currentColour).removeClass("pressed")}, 100);
}

function checkAnswer(currentLevel) {
    if(gamePattern[currentLevel] === userClickedPattern[currentLevel]) {
        if (currentLevel === level - 1) {
            setTimeout(function () {
                nextSequence();}, 600);
        }
    } else {
        $("body").addClass("game-over")
        setTimeout(function() {
            $("body").removeClass("game-over");
        }, 200);
        var wrongAudio = new Audio("./sounds/wrong.mp3");
        wrongAudio.play();
        $("#level-title").text("Game Over, Press Any Key to Restart");
        level = 0;
        gamePattern = [];
        gameStarted = false;
    }
}

方案二:动态绑定/解绑事件

如果一定要通过动态绑定事件来实现,可以在游戏开始时绑定点击事件,游戏结束时解绑;同时注意每次绑定前先解绑,避免重复绑定:

var buttonColours = ["red", "blue", "green", "yellow"];
var gamePattern = [];
var userClickedPattern = [];
var gameStarted = false;
var level = 0;

$(document).on("keydown", function (e){
    if (gameStarted===false) {
        gameStarted = true;
        level = 0;
        $("#level-title").text("Level " + level);
        // 游戏开始时绑定点击事件
        bindButtonClicks();
        nextSequence();
    }
});

function bindButtonClicks() {
    // 先解绑之前的事件,避免重复绑定
    $(".btn").off("click");
    $(".btn").on("click", function () {
        var userChosenColour = $(this).attr("id");
        userClickedPattern.push(userChosenColour);
        playSound(userChosenColour);
        animatePress(userChosenColour);
        checkAnswer(userClickedPattern.length - 1);
    });
}

function nextSequence() {
    userClickedPattern = [];
    level++;
    $("#level-title").text("Level " + level);
    var randomNumber = Math.floor(Math.random() * 4);
    var randomChosenColour = buttonColours[randomNumber];
    gamePattern.push(randomChosenColour);
    $("#" + randomChosenColour).fadeOut(100).fadeIn(100).fadeOut(100).fadeIn(100);
    playSound(randomChosenColour);  
}

function checkAnswer(currentLevel) {
    if(gamePattern[currentLevel] === userClickedPattern[currentLevel]) {
        if (currentLevel === level - 1) {
            setTimeout(function () {
                nextSequence();}, 600);
        }
    } else {
        $("body").addClass("game-over")
        setTimeout(function() {
            $("body").removeClass("game-over");
        }, 200);
        var wrongAudio = new Audio("./sounds/wrong.mp3");
        wrongAudio.play();
        $("#level-title").text("Game Over, Press Any Key to Restart");
        level = 0;
        gamePattern = [];
        gameStarted = false;
        // 游戏结束时解绑按钮点击事件
        $(".btn").off("click");
    }
}

function playSound(name) {
    var playAudio = new Audio("./sounds/"+name+".mp3");
    playAudio.play(); 
}

function animatePress(currentColour) {
    $("#" + currentColour).addClass("pressed");
    setTimeout(function() {
        $("#" + currentColour).removeClass("pressed")}, 100);
}

内容的提问来源于stack exchange,提问作者Kanaris

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 03:25:02