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

Canvas中mousedown事件失效:插入指定容器后方块无法移动

问题原因与解决方案

1. DOM元素获取时机错误

你把const gameBoard = document.querySelector('.game__board');写在脚本最外层,当脚本执行时,.game__board元素可能还没完成渲染,导致gameBoard为null,调用gameBoard.appendChild()会直接报错,游戏初始化流程中断。

修复方式:
把获取容器的代码移到startGame()函数内部,确保DOM已经加载完成,再传递给myGameArea.start()方法:

function startGame() {
    // 确保DOM加载完成后再获取元素
    const gameBoard = document.querySelector('.game__board');
    myGamePiece = new component(30, 30, "red", 10, 120);
    // ... 其他按钮初始化代码
    myGameArea.start(gameBoard);
}

var myGameArea = {
    canvas : document.createElement("canvas"),
    start : function(gameBoard) {
        this.canvas.width = 600;
        this.canvas.height = 600;
        this.context = this.canvas.getContext("2d");
        gameBoard.appendChild(this.canvas);
        // ... 其他初始化逻辑
    }
}

2. 鼠标坐标未转换为Canvas相对坐标

原来的代码用e.pageX/e.pageY获取的是整个文档的坐标,但现在Canvas放在.game__board容器里,容器可能有边距、定位等样式,导致文档坐标和Canvas内部的坐标系不匹配——游戏里的方块位置是基于Canvas自身坐标系的,所以点击坐标会偏差,无法触发按钮的点击判断。

修复方式:
通过canvas.getBoundingClientRect()获取Canvas在视口中的位置,将鼠标的视口坐标(e.clientX/e.clientY)转换为Canvas内部的相对坐标:

window.addEventListener('mousedown', function (e) {
    const canvasRect = myGameArea.canvas.getBoundingClientRect();
    // 计算相对于Canvas左上角的坐标
    myGameArea.x = e.clientX - canvasRect.left;
    myGameArea.y = e.clientY - canvasRect.top;
})

完整修正后的关键代码示例

<body onload="startGame()">
 <div id="game__board" class="game__board">
 </div>
 <script>
var myGamePiece;
var myUpBtn;
var myDownBtn;
var myLeftBtn;
var myRightBtn;

function startGame() {
    const gameBoard = document.querySelector('.game__board');
    myGamePiece = new component(30, 30, "red", 10, 120);
    myUpBtn = new component(30, 30, "blue", 50, 10);    
    myDownBtn = new component(30, 30, "blue", 50, 70);    
    myLeftBtn = new component(30, 30, "blue", 20, 40);    
    myRightBtn = new component(30, 30, "blue", 80, 40);                
    myGameArea.start(gameBoard);
}

var myGameArea = {
    canvas : document.createElement("canvas"),
    start : function(gameBoard) {
        this.canvas.width = 600;
        this.canvas.height = 600;
        this.context = this.canvas.getContext("2d");
        gameBoard.appendChild(this.canvas);
        this.interval = setInterval(updateGameArea, 20);
        window.addEventListener('mousedown', function (e) {
            const canvasRect = myGameArea.canvas.getBoundingClientRect();
            myGameArea.x = e.clientX - canvasRect.left;
            myGameArea.y = e.clientY - canvasRect.top;
        })
        window.addEventListener('mouseup', function (e) {
            myGameArea.x = false;
            myGameArea.y = false;
        })
    }
}

// 补全component和updateGameArea函数(假设原有逻辑)
function component(width, height, color, x, y) {
    this.width = width;
    this.height = height;
    this.x = x;
    this.y = y;
    this.update = function() {
        const ctx = myGameArea.context;
        ctx.fillStyle = color;
        ctx.fillRect(this.x, this.y, this.width, this.height);
    }
}

function updateGameArea() {
    myGameArea.context.clearRect(0, 0, myGameArea.canvas.width, myGameArea.canvas.height);
    // 按钮点击判断逻辑
    if (myGameArea.x && myGameArea.y) {
        if (myGameArea.x >= myUpBtn.x && myGameArea.x <= myUpBtn.x + myUpBtn.width &&
            myGameArea.y >= myUpBtn.y && myGameArea.y <= myUpBtn.y + myUpBtn.height) {
            myGamePiece.y -= 5;
        }
        if (myGameArea.x >= myDownBtn.x && myGameArea.x <= myDownBtn.x + myDownBtn.width &&
            myGameArea.y >= myDownBtn.y && myGameArea.y <= myDownBtn.y + myDownBtn.height) {
            myGamePiece.y += 5;
        }
        if (myGameArea.x >= myLeftBtn.x && myGameArea.x <= myLeftBtn.x + myLeftBtn.width &&
            myGameArea.y >= myLeftBtn.y && myGameArea.y <= myLeftBtn.y + myLeftBtn.height) {
            myGamePiece.x -= 5;
        }
        if (myGameArea.x >= myRightBtn.x && myGameArea.x <= myRightBtn.x + myRightBtn.width &&
            myGameArea.y >= myRightBtn.y && myGameArea.y <= myRightBtn.y + myRightBtn.height) {
            myGamePiece.x += 5;
        }
    }
    // 更新所有元素
    myGamePiece.update();
    myUpBtn.update();
    myDownBtn.update();
    myLeftBtn.update();
    myRightBtn.update();
}
 </script>
</body>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 20:05:26