如何为动态创建的正方形div绑定点击事件实现Etch-a-Sketch
Etch-a-Sketch 动态网格事件绑定实现方案
动态生成的DOM元素无法通过页面初始化时的元素选择直接绑定事件,有两种可落地的实现方式,根据你的场景选择即可:
方案1:元素创建阶段直接绑定
你在循环里用createElement生成每个格子div的时候,这个节点已经存在于内存中了,可以直接在append到页面前给它绑定事件监听,不需要等插入DOM后再查找。
修改后的核心JS代码如下:
let container = document.getElementById('container'); function getGrid(gridNumber) { // 生成新网格前清空旧内容 container.innerHTML = ''; // 动态匹配网格列数,替换原来CSS里写死的16列配置 container.style.gridTemplateColumns = `repeat(${gridNumber}, 1fr)`; for (let i = 1; i <= gridNumber * gridNumber; i++) { const row = document.createElement('div'); row.style.border = '1px solid red' row.classList.add('box'); // 直接给当前创建的格子绑定点击响应 row.addEventListener('click', function() { // 点击后修改背景色,实现涂色效果 this.style.backgroundColor = '#222'; }) container.appendChild(row); } } getGrid(16);
- 适用场景:网格尺寸小(比如低于20*20)、每个格子有独立自定义逻辑的场景
- 缺点:网格密度高时(比如100*100=10000个格子),会生成大量重复的事件监听器,内存开销高
方案2:事件委托(推荐)
利用DOM事件冒泡的特性,只需要给所有格子的父容器#container绑定1个事件监听器,就能响应所有子元素的触发事件,自动兼容后续任意时刻动态插入的格子,不需要重复绑定。
核心实现代码:
let container = document.getElementById('container'); // 页面加载完成后只绑定一次,全局生效 container.addEventListener('click', (e) => { // 过滤非格子元素的触发事件 if (e.target.matches('.box')) { // 给当前点击的格子涂色 e.target.style.backgroundColor = '#222'; } }) function getGrid(gridNumber) { container.innerHTML = ''; container.style.gridTemplateColumns = `repeat(${gridNumber}, 1fr)`; for (let i = 1; i <= gridNumber * gridNumber; i++) { const row = document.createElement('div'); row.style.border = '1px solid red' row.classList.add('box'); // 循环内不需要再给单个格子绑监听 container.appendChild(row); } } getGrid(16);
- 优势:
- 性能开销极低,不管网格开多大,都只有1个监听器
- 后续调整网格尺寸、重新生成格子时不需要重复绑定事件
- 扩展按住鼠标拖动涂色、随机色涂色等经典Etch-a-Sketch交互时,逻辑改动量极小
小提示:如果要实现经典的按住拖动连续涂色效果,只需要额外加一个全局的鼠标按下状态标记,配合委托的
mouseover事件即可实现,不需要修改网格生成逻辑。
内容的提问来源于stack exchange,提问作者Master1
相关产品推荐
相关产品推荐

