React中实现按住鼠标拖动修改二维Div矩阵颜色的技术问询
实现React矩阵单元格的拖拽着色功能
要实现按住鼠标左键移动时给经过的矩阵单元格着色,你需要结合几个鼠标事件完成,同时要遵循React状态驱动UI的理念,不要直接操作DOM样式。
需要用到的核心事件
onMouseDown:按下鼠标左键时,标记开始着色状态,并给当前单元格上色onMouseMove:鼠标移动时,如果处于着色状态,给经过的单元格上色onMouseUp/onMouseLeave:松开鼠标或鼠标移出画布时,结束着色状态
你的现有代码问题
- 直接修改DOM元素的
style.backgroundColor,不符合React状态管理规范,应该通过更新state让React自动渲染颜色变化 - 只绑定了
onClick,无法处理拖拽过程中的连续着色 - 渲染逻辑存在错误:
const clr = x.color应该取y.clr(x是行数组,y才是单个单元格对象);className里的x.x重复,应该用单元格自身的坐标标识
修改后的完整代码
import { useState, useEffect, useCallback } from "react"; function Grid() { const [canvas, setCanvas] = useState([[]]); const [isDrawing, setIsDrawing] = useState(false); // 创建30x30的初始矩阵 const createGrid = () => { const newGrid = []; for (let i = 0; i < 30; i++) { newGrid.push([]); for (let j = 0; j < 30; j++) { newGrid[i].push({ x: i, y: j, clr: "white" }); } } setCanvas(newGrid); }; useEffect(createGrid, []); // 更新单元格颜色的通用方法 const updateCellColor = useCallback((x, y) => { setCanvas(prevGrid => { const newGrid = [...prevGrid]; newGrid[x][y] = { ...newGrid[x][y], clr: "red" }; return newGrid; }); }, []); // 鼠标按下:启动着色模式并给当前单元格上色 const handleMouseDown = useCallback((e) => { const cell = e.target.dataset; updateCellColor(Number(cell.x), Number(cell.y)); setIsDrawing(true); }, [updateCellColor]); // 鼠标移动:如果处于着色模式,给经过的单元格上色 const handleMouseMove = useCallback((e) => { if (!isDrawing) return; const cell = e.target.dataset; if (cell.x && cell.y) { updateCellColor(Number(cell.x), Number(cell.y)); } }, [isDrawing, updateCellColor]); // 鼠标松开/移出画布:结束着色模式 const handleMouseUp = useCallback(() => { setIsDrawing(false); }, []); const handleMouseLeave = useCallback(() => { setIsDrawing(false); }, []); return ( <div className="canvas" onMouseUp={handleMouseUp} onMouseLeave={handleMouseLeave} style={{ display: "flex", flexDirection: "column" }} > {canvas.map((row, rowIndex) => ( <div key={rowIndex} className="row"> {row.map((cell) => ( <div key={`${cell.x}-${cell.y}`} className="cell" data-x={cell.x} data-y={cell.y} style={{ backgroundColor: cell.clr, width: "20px", height: "20px", border: "1px solid #ccc" }} onMouseDown={handleMouseDown} onMouseMove={handleMouseMove} /> ))} </div> ))} </div> ); } export default Grid;
代码说明
isDrawing状态用于跟踪是否处于着色模式,避免误触- 使用
useCallback包裹事件处理函数,避免组件重渲染时创建新函数实例,提升性能 - 通过
data-x/data-y属性存储单元格坐标,方便事件中获取位置信息 - 所有颜色更新都通过修改state实现,完全遵循React状态驱动UI的原则
- 在父容器上绑定
onMouseUp和onMouseLeave,确保鼠标移出单个单元格时也能正确结束着色
内容的提问来源于stack exchange,提问作者Anurag-210
相关产品推荐
相关产品推荐

