不使用canvas元素实现鼠标点击绘画的Etch-A-Sketch问题求教
问题核心原因
你遇到的异常是两个核心问题导致的:
- 所有
mouseover事件的回调逻辑里没有校验isDrawing状态,只要鼠标划过格子就会直接上色,和是否按住鼠标无关 - 每次点击颜色按钮都会给所有格子新增一次
mouseover监听,多次点击后事件会重复触发,逻辑冗余还会有性能隐患
解决思路
我们可以统一管理上色逻辑和事件监听,避免重复绑定:
- 新增一个全局变量存储当前选中的上色规则,点击不同功能按钮时只需更新这个变量的赋值即可
- 只给所有格子绑定一次
mouseover事件,触发时先判断isDrawing是否为true,再执行对应的上色逻辑 - 额外补充点击格子时直接上色的逻辑,避免按下鼠标的第一个格子无法被绘制
修复后的完整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
相关产品推荐
相关产品推荐

