You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

蚀刻素描网格按钮失效:无法读取null的addEventListener属性

问题修复:蚀刻素描网格按钮失效与"无法读取null的addEventListener属性"错误

错误根源

  1. 集合而非单个元素:getElementsByClassName返回的是HTMLCollection(元素集合),直接对集合调用addEventListener会报错——集合没有这个方法。
  2. 未定义变量:按钮点击事件里的number变量从未声明,调用makeColumn(number, ...)会触发报错。
  3. 逻辑错误:当前点击按钮就重新生成所有单元格的逻辑不合理,应维护一个「当前绘图颜色」的状态,在鼠标进入单元格时应用该状态,而非重建网格。
  4. 索引错误: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 10:24:12