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

如何实现双玩家创建共用模态框并限制标记互斥?

Tic-Tac-Toe玩家创建模态框的互斥标记实现方案

我正在为Odin Project开发Tic-Tac-Toe游戏,现有两个Enter Player按钮,点击后希望打开同一个模态框,分别输入两个玩家的参数并保存。需求是:当一个玩家选择X作为标记后,另一个玩家无法选择X,只能选O,请问该怎么实现?


现有代码

HTML

<body>
    <header> TIC-TAC-TOE</header>
    <section id="large-container">
        <article class="Players" id="player1">
            Player1
            <button id="player1-btn">
                Enter Player
            </button>
        </article>
        <div class="container">
            <div class="item"><button id="cell0">0</button></div>
            <div class="item"><button id="cell1">1</button></div>
            <div class="item"><button id="cell2">2</button></div>
            <div class="item"><button id="cell3">3</button></div>
            <div class="item"><button id="cell4">4</button></div>
            <div class="item"><button id="cell5">5</button></div>
            <div class="item"><button id="cell6">6</button></div>
            <div class="item"><button id="cell7">7</button></div>
            <div class="item"><button id="cell8">8</button></div>
        </div>
        <article class="Players" id="player2">
            Player2
            <button id="player2-btn">
                Enter Player
            </button>
        </article>
        <dialog class="PlayerDialog">
            <form>
                <p>
                    <label for="playerName">What is the Player's Name</label>
                    <input type="text" id="PName" name="PName">

                    <label for="playerMarker">What is the Players marker?
                        <select id="markerSelect">
                            <option value="X" id="X" name="Marker">X</option>
                            <option value="O" id="O" name="Marker">O</option>
                        </select>
                    </label>
                </p>
                <button value="cancel" formmethod="dialog">Cancel</button>
                <button id="Confirm" value="default">Confirm</button>
            </form>
        </dialog>
    </section>
    <script src="Main3.js"></script>
</body>

注:已修正原代码中ID重复的问题(原article和button共享同一ID,棋盘按钮ID也重复),避免DOM选择逻辑出错。

原JS代码

const playerCreationButtons = document.querySelectorAll(".Players > button")
const playerCreation = document.querySelector(".PlayerDialog")
const PlayerDisplay = document.querySelector("article.Players")
const confirmBtn = document.querySelector("#Confirm")
const playerName = document.getElementById("#PName") // 此处多了#,属于选择错误
const playerMarkerX = document.getElementById("X")
playerCreationButtons.forEach((button)=>{
    button.addEventListener("click", ()=>{
         /// (Some code here to alter the modal for each player before it's shown)///
        playerCreation.showModal()
        console.log(`${button.id}`)
    })
})

实现方案

核心思路:用变量记录已被选择的标记,打开模态框时根据已选状态禁用对应选项;同时跟踪当前编辑的玩家ID,确认后保存信息并更新标记状态。

修改后的JS代码如下:

// 获取DOM元素
const playerCreationButtons = document.querySelectorAll(".Players > button");
const playerCreationDialog = document.querySelector(".PlayerDialog");
const confirmBtn = document.querySelector("#Confirm");
const playerNameInput = document.getElementById("PName"); // 修正ID选择错误
const markerSelect = document.getElementById("markerSelect");
const xOption = document.getElementById("X");
const oOption = document.getElementById("O");

// 存储玩家信息和已选标记
const players = {
    player1: { name: "Player1", marker: null },
    player2: { name: "Player2", marker: null }
};
let currentEditingPlayer = null; // 记录当前正在编辑的玩家ID

// 玩家按钮点击事件:初始化模态框并打开
playerCreationButtons.forEach((button) => {
    button.addEventListener("click", () => {
        // 从按钮ID提取当前编辑的玩家标识
        currentEditingPlayer = button.id.replace("-btn", "");
        const targetPlayer = players[currentEditingPlayer];

        // 初始化输入框:填充已有玩家名称
        playerNameInput.value = targetPlayer.name;

        // 根据已选标记设置选项禁用状态
        const usedMarker = players.player1.marker || players.player2.marker;
        if (usedMarker) {
            // 禁用已被选择的标记,强制选中剩余标记
            if (usedMarker === "X") {
                xOption.disabled = true;
                markerSelect.value = "O";
            } else {
                oOption.disabled = true;
                markerSelect.value = "X";
            }
        } else {
            // 无标记被选中时,恢复所有选项可用
            xOption.disabled = false;
            oOption.disabled = false;
            markerSelect.value = "X"; // 默认选中X
        }

        playerCreationDialog.showModal();
    });
});

// 确认按钮事件:保存玩家信息
confirmBtn.addEventListener("click", (e) => {
    e.preventDefault(); // 阻止表单默认提交行为
    if (!currentEditingPlayer) return;

    // 获取输入值,无输入时使用默认名称
    const name = playerNameInput.value.trim() || `Player${currentEditingPlayer.slice(-1)}`;
    const marker = markerSelect.value;

    // 保存玩家信息到对象
    players[currentEditingPlayer] = { name, marker };
    // 更新页面上的玩家名称显示
    document.getElementById(currentEditingPlayer).textContent = name;

    // 关闭模态框并重置输入
    playerCreationDialog.close();
    playerNameInput.value = "";
});

// 模态框关闭事件:重置编辑状态
playerCreationDialog.addEventListener("close", () => {
    currentEditingPlayer = null;
    playerNameInput.value = "";
    // 恢复所有标记选项可用(支持重新编辑玩家信息)
    xOption.disabled = false;
    oOption.disabled = false;
});

关键逻辑说明

  • 标记互斥控制:打开模态框时检查另一个玩家的标记,若已有玩家选择X,则禁用X选项并强制当前玩家选O,反之亦然。
  • 玩家状态跟踪:用currentEditingPlayer变量记录当前编辑对象,确保信息保存到对应玩家的存储空间。
  • 用户体验优化:打开模态框时自动填充已有玩家名称,取消操作后重置输入状态。
  • ID规范修正:原代码中重复ID会导致DOM选择异常,已统一修改为唯一ID(如player1、player1-btn)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 17:25:11