etch-a-sketch项目如何实现鼠标按下后触发mouseover变色效果
Etch-a-Sketch 按住鼠标触发绘制实现方案
问题背景
开发The Odin Project的etch-a-sketch项目时,原有交互为鼠标悬停网格元素即触发颜色变化,需要调整为仅按住鼠标左键状态下,鼠标悬停网格才触发变色绘制,匹配常规画板拖拽绘制的交互逻辑。
核心实现逻辑
通过全局状态变量标记鼠标左键的按下状态,仅在状态为按下时执行变色逻辑:
- 全局监听鼠标按下、松开事件,更新状态标记
- 网格的悬停变色逻辑增加状态判断,非按下状态直接终止执行
- 补充网格点击即上色的逻辑,优化单点绘制体验
- 修复原有代码中多元素共用同个id的规范问题
具体代码修改步骤
1. 新增全局状态变量
在JS文件顶部的变量声明区域,添加鼠标状态标记:
let isMouseDown = false; // 标记鼠标左键是否处于按下状态
2. 绑定全局鼠标状态监听
在createGrid()函数调用前,添加全局事件监听,同步鼠标按下/松开状态,同时阻止浏览器默认拖拽选中的干扰行为:
// 监听鼠标左键按下 document.addEventListener('mousedown', (e) => { if (e.button === 0) isMouseDown = true; }) // 监听鼠标左键松开 document.addEventListener('mouseup', (e) => { if (e.button === 0) isMouseDown = false; }) // 阻止原生拖拽选中文本的默认行为,避免绘制干扰 document.addEventListener('dragstart', (e) => e.preventDefault())
3. 修改变色函数增加状态判断
在changeColor函数最开头添加状态校验,非按下状态直接返回,不执行变色逻辑:
function changeColor(e) { // 鼠标未按下时直接终止逻辑 if (!isMouseDown) return; // 下方保留原有所有变色逻辑,无需修改 if (mode === 'pencil') { e.target.classList.add('black'); e.target.classList.remove('white'); e.target.style.backgroundColor = null; e.target.style.opacity = null; } else if (mode === 'rainbow') { const green = Math.floor(Math.random() * 250); const blue = Math.floor(Math.random() * 250); const red = Math.floor(Math.random() * 250); e.target.style.backgroundColor = `rgb(${red}, ${green}, ${blue})`; e.target.style.opacity = null; } else if (mode === 'erase') { e.target.classList.add('white'); e.target.style.backgroundColor = null; e.target.style.opacity = null; } else if (mode === 'pickColor') { e.target.style.backgroundColor = pickColor.value; e.target.style.opacity = null; } else if (mode === 'shading') { e.target.classList.remove('white'); e.target.classList.add('black'); e.target.style.opacity = Number(e.target.style.opacity) + 0.2; } else { e.target.classList.add('black') } }
4. 调整网格创建逻辑
修改createGrid函数,将重复的id改为符合规范的class,同时给网格添加鼠标按下即触发变色的事件,优化单点点击绘制体验:
function createGrid(size) { size = gridSize.value; container.style.gridTemplateColumns = `repeat(${size}, 1fr)`; container.style.gridTemplateRows = `repeat(${size}, 1fr)`; for (let i = 0; i < size * size; i++) { const grid = document.createElement('div'); // 原id="grid"改为class,id需全局唯一,多元素同类样式用class grid.classList.add('grid'); container.appendChild(grid); grid.addEventListener('mouseover', changeColor); // 新增:鼠标直接点击网格时也触发变色 grid.addEventListener('mousedown', changeColor); } }
5. 同步修改CSS选择器
将CSS中原有的#grid选择器改为.grid,匹配刚才的class修改,保证网格样式正常生效:
.grid { border: none; }
内容的提问来源于stack exchange,提问作者fallenech
相关产品推荐
相关产品推荐

