You need to enable JavaScript to run this app. 不使用canvas元素实现鼠标点击绘画的Etch-A-Sketch问题求教
优惠活动
大模型
产品
解决方案
定价
更多

不使用canvas元素实现鼠标点击绘画的Etch-A-Sketch问题求教

问题核心原因

你遇到的异常是两个核心问题导致的:

  • 所有mouseover事件的回调逻辑里没有校验isDrawing状态,只要鼠标划过格子就会直接上色,和是否按住鼠标无关
  • 每次点击颜色按钮都会给所有格子新增一次mouseover监听,多次点击后事件会重复触发,逻辑冗余还会有性能隐患

解决思路

我们可以统一管理上色逻辑和事件监听,避免重复绑定:

  1. 新增一个全局变量存储当前选中的上色规则,点击不同功能按钮时只需更新这个变量的赋值即可
  2. 只给所有格子绑定一次mouseover事件,触发时先判断isDrawing是否为true,再执行对应的上色逻辑
  3. 额外补充点击格子时直接上色的逻辑,避免按下鼠标的第一个格子无法被绘制

修复后的完整JS代码

"use strict";

const divContainer = document.querySelector(".container");
const btnsContainer = document.querySelector(".buttons");
const btnBlack = document.createElement("button");
const btnGreyScale = document.createElement("button");
const btnRgb = document.createElement("button");
const btnErase = document.createElement("button");
const btnShake = document.createElement("button");

function createGrid(col, rows) {
  for(let i = 0; i < (col * rows); i++) {
      const div = document.createElement("div"); 
      divContainer.style.gridTemplateColumns = `repeat(${col}, 1fr)`;
      divContainer.style.gridTemplateRows = `repeat(${rows}, 1fr)`;
      divContainer.appendChild(div).classList.add("box");
  }
}
createGrid(16,16)

let isDrawing = false;
// 新增变量存储当前选中的上色方法
let currentPaint = () => {};

window.addEventListener("mousedown", (e) => {
    isDrawing = true;
    // 点击到格子时直接上色一次,避免第一个格子画不到
    if (e.target.classList.contains('box')) {
      currentPaint(e.target);
    }
});
window.addEventListener("mouseup", () => {
    isDrawing = false;
});

// 统一绑定一次mouseover事件
const boxes = divContainer.querySelectorAll(".box");
boxes.forEach(box => {
  box.addEventListener("mouseover", function() {
    if (isDrawing) {
      currentPaint(this);
    }
  })
})

function paintBlack() { 
  btnBlack.textContent = "Black";
  btnBlack.addEventListener("click", function () {
    // 点击按钮只更新currentPaint的赋值
    currentPaint = (el) => {
      el.style.background = "#000";
    }
  })
  btnsContainer.appendChild(btnBlack).classList.add("btn");
}
paintBlack();

function paintGreyScale() { 
  btnGreyScale.textContent = "Grey";
  btnGreyScale.addEventListener("click", function () {
    currentPaint = (el) => {
      let randNum = Math.floor(Math.random() * 256);
      let grayScale = `rgb(${randNum},${randNum},${randNum})`;
      el.style.background = grayScale;
    }
  })
  btnsContainer.appendChild(btnGreyScale).classList.add("btn");
}
paintGreyScale();

function paintRgb() { 
  btnRgb.textContent = "Rainbow";
  btnRgb.addEventListener("click", function () {
    currentPaint = (el) => {
      let r = Math.floor(Math.random() * 256);
      let g = Math.floor(Math.random() * 256);
      let b = Math.floor(Math.random() * 256);
      const rgb = `rgb(${r},${g},${b})`;
      el.style.background = rgb;
    }
  })
  btnsContainer.appendChild(btnRgb).classList.add("btn");
}
paintRgb();

function erase() { 
  btnErase.textContent = "Erase";
  btnErase.addEventListener("click", function () {
    currentPaint = (el) => {
      el.style.background = "#FFF";
    }
  })
  btnsContainer.appendChild(btnErase).classList.add("btn");
}
erase();

function clearCanvas() { 
  const boxes = divContainer.querySelectorAll(".box");
  boxes.forEach(box => box.style.backgroundColor = "#FFF");
}
// 优化clearCanvas逻辑,去掉重复绑定
btnShake.textContent = "Shake it!";
btnShake.addEventListener("click", clearCanvas);
btnsContainer.appendChild(btnShake).classList.add("shake");

内容的提问来源于stack exchange,提问作者e-d-i

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.11 03:06:02