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

如何在JavaScript中清除鼠标坐标处的矩形且不影响其他图形?

解决方案

你的代码核心问题有两个:一是把mousemove事件监听放在了渲染循环loop里,每次循环都会新增一个监听,导致鼠标移动时重复绘制矩形;二是鼠标矩形的绘制脱离了统一的渲染流程,和网格的绘制不同步,所以清屏时要么全清要么无法单独处理旧的鼠标矩形。

下面是修复后的完整代码,实现鼠标跟随矩形且不影响网格:

<!DOCTYPE html>
<html>
  <style>
     html, body {
    height: 100%;
    margin: 0;
  }

  body {
    display: flex;
    align-items: center;
    justify-content: center;
  }

  canvas {
    border: 1px solid orange;
    background: black;
  }
  </style>
  <head>
    <base target="_top">
  </head>
  <body>
<canvas width="1250" height="600" id="game"></canvas>
    <script>
const canvas = document.getElementById('game');
const ctx = canvas.getContext('2d');
// 存储鼠标位置,初始设到画布外避免初始绘制
let mousePos = { x: -100, y: -100 };
// 网格参数提前定义,不用每次循环重复声明
const levelMax = 5;
const gridBoxSize = 75;

// 鼠标事件监听放外面,只绑定一次
window.addEventListener("mousemove", (e)=>{
  mousePos.x = e.offsetX;
  mousePos.y = e.offsetY;
});

function loop(){
  // 每次循环先全清画布,统一重绘所有元素
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  
  // 绘制网格盒子
  ctx.fillStyle = "lime";
  for (let j = 0; j < levelMax; j++) {
    for (let i = 0; i < levelMax; i++) {
      const x = gridBoxSize * i;
      const y = 525 - (j * gridBoxSize);
      ctx.fillRect(x, y, gridBoxSize, gridBoxSize);
    }
  }
  
  // 绘制鼠标跟随的矩形(换个颜色区分网格)
  ctx.fillStyle = "white";
  ctx.fillRect(mousePos.x, mousePos.y, 50, 50);
  
  requestAnimationFrame(loop);
}
loop();
    </script>
  </body>
</html>

关键修改说明:

  • 把mousemove监听移到loop外面,避免重复绑定事件导致多次绘制。
  • 用mousePos变量存储鼠标坐标,在loop里统一绘制鼠标矩形,这样每次清屏后会重新画所有元素,旧的鼠标矩形自然被清除,新的随鼠标位置更新。
  • 删掉了没用的box数组,直接计算网格坐标绘制,简化代码。

如果担心全清画布的性能(比如网格元素很多),可以只清除上一次的鼠标矩形,再绘制新的,但这种方式要注意修复被清除的网格部分:

// 新增变量存储上一次鼠标位置
let lastMousePos = { x: -100, y: -100 };
const mouseBoxSize = 50;

window.addEventListener("mousemove", (e)=>{
  // 清除上一次的鼠标矩形
  ctx.clearRect(lastMousePos.x, lastMousePos.y, mouseBoxSize, mouseBoxSize);
  // 修复被清除的网格部分(重新绘制对应区域的网格)
  redrawGridArea(lastMousePos.x, lastMousePos.y, mouseBoxSize);
  
  // 更新当前鼠标位置并绘制新矩形
  mousePos.x = e.offsetX;
  mousePos.y = e.offsetY;
  ctx.fillStyle = "white";
  ctx.fillRect(mousePos.x, mousePos.y, mouseBoxSize, mouseBoxSize);
  
  // 记录当前位置为下一次清除用
  lastMousePos = { ...mousePos };
});

// 重新绘制指定区域内的网格盒子
function redrawGridArea(clearX, clearY, clearSize) {
  ctx.fillStyle = "lime";
  for (let j = 0; j < levelMax; j++) {
    for (let i = 0; i < levelMax; i++) {
      const gridX = gridBoxSize * i;
      const gridY = 525 - (j * gridBoxSize);
      // 检查网格是否和清除区域重叠
      if (gridX < clearX + clearSize && gridX + gridBoxSize > clearX &&
          gridY < clearY + clearSize && gridY + gridBoxSize > clearY) {
        ctx.fillRect(gridX, gridY, gridBoxSize, gridBoxSize);
      }
    }
  }
}

function loop(){
  // 初始化绘制一次网格
  ctx.fillStyle = "lime";
  for (let j = 0; j < levelMax; j++) {
    for (let i = 0; i < levelMax; i++) {
      const x = gridBoxSize * i;
      const y = 525 - (j * gridBoxSize);
      ctx.fillRect(x, y, gridBoxSize, gridBoxSize);
    }
  }
  
  requestAnimationFrame(loop);
}
loop();

这种方式适合网格固定的场景,但代码复杂度更高,一般推荐全清画布统一重绘的方式,逻辑更简单不易出错。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 17:54:50