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

Vanilla JavaScript渲染对象数组报错:Cannot read properties of null

问题分析与修复方案

错误原因

  1. 提前获取不存在的DOM元素:代码开头定义的nameEl、jobEl、task、deleteBtn变量,试图获取页面初始加载时不存在的元素(这些元素是点击按钮后才渲染生成的),所以getElementById返回null,触发Cannot read properties of null错误。而且这些变量后续并未使用,属于冗余代码。
  2. 重复渲染与文档片段滥用:全局的list文档片段会被重复添加内容,且未清空itemsEl容器,导致多次点击按钮后任务会重复显示。
  3. 重复ID属性:渲染任务时给每个任务的标题、按钮都用了相同ID(如name、deleteBtn),违反HTML中ID必须唯一的规则,会导致后续DOM操作混乱。
  4. 不当的数组遍历方法:遍历数组仅为渲染元素,无需返回新数组,用forEach比map更贴合场景。

修复后的代码

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">
    <link rel="stylesheet" href="./index.css">
    <title>Document</title>
</head>
<body>
    <div class="container">
        <input id="nameInput" placeholder="enter name" >
        <input id="jobInput" placeholder="enter job" >
        <input id="taskInput" placeholder="enter task" >
        <button id="addBtn">Add Task</button>
        <div class="items"></div>
    </div>
    <script src="./index.js"></script>
</body>
</html>

JavaScript

const data = [];
const itemsEl = document.getElementById("items");
const addBtn = document.getElementById("addBtn");

function addItem() {
    const name = document.getElementById("nameInput").value;
    const job = document.getElementById("jobInput").value;
    const task = document.getElementById("taskInput").value;
    // 过滤空内容,避免添加无效任务
    if (!name.trim() || !job.trim() || !task.trim()) return;
    data.push({ name, job, task });
    displayData();
    // 清空输入框,提升体验
    document.getElementById("nameInput").value = "";
    document.getElementById("jobInput").value = "";
    document.getElementById("taskInput").value = "";
}

function displayData() {
    // 先清空容器,防止重复渲染
    itemsEl.innerHTML = "";
    const list = document.createDocumentFragment();
    data.forEach(({ name, job, task }, index) => {
        const itemDiv = document.createElement("div");
        itemDiv.className = "task-item";
        itemDiv.innerHTML = `
            <h1 class="name">${name}</h1>
            <h3 class="job">${job}</h3>
            <h4 class="task">${task}</h4>
            <button class="deleteBtn" data-index="${index}">Delete Task</button>
        `;
        list.appendChild(itemDiv);
    });
    itemsEl.appendChild(list);
}

// 事件委托处理删除操作,无需给每个按钮单独绑定事件
itemsEl.addEventListener("click", (e) => {
    if (e.target.classList.contains("deleteBtn")) {
        const index = parseInt(e.target.dataset.index);
        data.splice(index, 1);
        displayData();
    }
});

addBtn.addEventListener("click", addItem);

额外优化说明

  • 增加输入内容校验,避免添加空任务。
  • 点击添加后自动清空输入框,优化用户体验。
  • 使用事件委托处理删除按钮,更高效且避免重复绑定事件。
  • 给任务项添加统一类名task-item,方便后续样式定制。
  • 用data-index存储任务在数组中的索引,简化删除时的定位逻辑。

内容的提问来源于stack exchange,提问作者Otonye Amietubodie

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 03:25:27