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
相关产品推荐
相关产品推荐

