蚀刻素描网格按钮失效:无法读取null的addEventListener属性
问题修复:蚀刻素描网格按钮失效与"无法读取null的addEventListener属性"错误
错误根源
- 集合而非单个元素:
getElementsByClassName返回的是HTMLCollection(元素集合),直接对集合调用addEventListener会报错——集合没有这个方法。 - 未定义变量:按钮点击事件里的
number变量从未声明,调用makeColumn(number, ...)会触发报错。 - 逻辑错误:当前点击按钮就重新生成所有单元格的逻辑不合理,应维护一个「当前绘图颜色」的状态,在鼠标进入单元格时应用该状态,而非重建网格。
- 索引错误:
makeColumn里的rows[j].appendChild(column)用错了索引,应使用行循环的i而非列循环的j。
修复方案
1. 正确获取按钮元素
用querySelector直接选中单个按钮元素,而非获取集合:
const blueBtn = document.querySelector('.blue'); const eraserBtn = document.querySelector('.eraser'); const blackBtn = document.querySelector('.black'); const resetBtn = document.querySelector('.reset');
2. 维护当前绘图状态
新增变量存储当前选中的颜色/模式,鼠标进入单元格时应用这个状态:
let currentColor = 'colored'; // 默认红色
3. 重构单元格着色逻辑
统一鼠标进入事件的逻辑,根据当前状态添加对应类名,无需在创建单元格时绑定固定逻辑:
function handleCellEnter(e) { // 先移除所有可能的着色类,避免类叠加 e.target.classList.remove('colored', 'blue', 'eraser', 'black'); e.target.classList.add(currentColor); }
4. 修正按钮点击事件
点击按钮时只更新currentColor状态,无需重建网格:
blueBtn.addEventListener('click', () => { currentColor = 'blue'; }); eraserBtn.addEventListener('click', () => { currentColor = 'eraser'; }); blackBtn.addEventListener('click', () => { currentColor = 'black'; });
5. 修正网格创建时的索引错误
把rows[j].appendChild(column)改为rows[i].appendChild(column),确保单元格添加到对应行。
完整修复代码
HTML(无需修改)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>DOM Manipulation and Events</title> <script src="javascript.js" defer></script> <link rel="stylesheet" href="styles.css"> </head> <body> <h1 class="header"> Let's sketch ! </h1> <div id="setGridSize"> <p> Grid size </p> <input type="text" placeholder="Size of Board" class="size-box"> <button id="submit" > Submit </button> </div> <p id="guide"> Enter a number between 2 to 99</p> <div class="container"></div> <div class="buttons"> <button class="blue"> Blue </button> <button class="eraser" > Eraser </button> <button class="black"> Black </button> <button class="rainbow" > Rainbow </button> <button class="reset" > Reset</button> </div> </body> </html>
CSS(修正语法与布局问题)
@import url('https://fonts.googleapis.com/css2?family=Asap:wght@400;600;700&display=swap'); body { display: flex; height: 100vh; width: 100%; flex-direction: column; background-color: beige; font-family: Asap, sans-serif; margin: 0; padding: 0; justify-content: center; align-content: center; align-items: center; } .header { display: flex; flex: 1; justify-content: center; } #setGridSize { display: inline-flex; justify-content: center; flex: 1; gap: 12px; } #guide { text-align: center; margin: 1px; font-family: Asap, sans-serif; color: red; font-size: 13px;; } .container { display: flex; flex-direction: column; justify-content: center; align-content: center; align-items: center; border: 1px solid black; width: 550px; height: 550px; } .gridRow { display: flex; } .gridColumn { border: 1px solid beige; margin: -1px; width: 30px; height: 30px; } .colored{ background: red; } .buttons { display: flex; flex: 1; gap: 20px; margin: 10px; } .blue { background: blue; color: white; } .eraser { background: white; } .black { background: black; color: white; }
JavaScript(完整修复)
let container = document.querySelector('.container'); let currentColor = 'colored'; const blueBtn = document.querySelector('.blue'); const eraserBtn = document.querySelector('.eraser'); const blackBtn = document.querySelector('.black'); const resetBtn = document.querySelector('.reset'); function createGrid(number) { container.innerHTML = ''; makeRow(number); makeColumn(number); } function makeRow(numberOfRow) { for (let i = 0; i < numberOfRow; i++) { let row = document.createElement('div'); container.appendChild(row); row.classList.add('gridRow'); } } function makeColumn(numberOfColumn) { const rows = document.getElementsByClassName('gridRow'); for (let i = 0; i < rows.length; i++) { for (let j = 0; j < numberOfColumn; j++) { let column = document.createElement('div'); column.classList.add('gridColumn'); column.addEventListener('mouseenter', handleCellEnter); rows[i].appendChild(column); } } } function handleCellEnter(e) { e.target.classList.remove('colored', 'blue', 'eraser', 'black'); e.target.classList.add(currentColor); } blueBtn.addEventListener('click', () => { currentColor = 'blue'; }); eraserBtn.addEventListener('click', () => { currentColor = 'eraser'; }); blackBtn.addEventListener('click', () => { currentColor = 'black'; }); resetBtn.addEventListener('click', () => { createGrid(16); }); createGrid(16);
额外优化点
- 修正CSS中
@import的语法错误(缺少空格) - 给容器添加
flex-direction: column确保行垂直排列 - 给行添加
display: flex确保单元格横向排列 - 修正单元格margin为
-1px解决边框重叠问题 - 给深色按钮添加白色文字,提升可读性
- 实现重置按钮功能,点击后重新生成16×16网格
内容的提问来源于stack exchange,提问作者Jabri Juhinin
相关产品推荐
相关产品推荐

