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

removeChild()功能正常但抛出参数非Node类型错误排查

错误根源

你遇到的报错是删除按钮重复绑定事件+重复ID+单本书生成多个删除按钮三个问题共同导致的:

  • 违反HTML ID唯一性规范:你给所有删除按钮都设置了相同的iddelete-btn,每次新增书籍后调用document.querySelectorAll('#delete-btn')会选中页面上所有历史生成的删除按钮,而非仅新创建的按钮。
  • 事件重复绑定:每新增一本书,你就会遍历全量删除按钮,给每个按钮再追加一次相同的点击回调。比如添加3本书后,第一本书的删除按钮上会绑定3次完全相同的删除逻辑。点击按钮时第一次回调执行成功删除对应DOM节点,后续回调执行时目标节点已经被移除,document.getElementById()返回null,将null作为参数传入removeChild()就会触发「参数不是Node类型」的报错,这也是为什么你看到删除功能正常但控制台抛错。
  • 冗余按钮生成:你把删除按钮的创建逻辑写在了遍历书籍属性的for...in循环内部,一本书有多少个属性(作者、标题、页数、阅读状态共4个),就会在卡片里生成多少个叠放在同一位置的删除按钮,进一步放大了重复绑定的问题。
修复方法
  1. 把删除按钮的创建逻辑移到属性遍历的for循环外部,保证单本书卡片只生成1个删除按钮
  2. 用class代替重复id标记删除按钮
  3. 删除全局遍历删除按钮绑定事件的逻辑,改为创建新按钮时直接给当前按钮绑定单次事件
  4. 增加节点存在性判断,极端场景下也不会抛错

修复后的核心JS代码如下:

const books = [];
const newBook = document.getElementById('new-book');
const form = document.querySelector('form');
const formButton = document.getElementById('form-button');
const content = document.querySelector('.content');

newBook.addEventListener('click', e => {
    toggleForm();
})

function toggleForm() {
    form.classList.toggle('form-hidden');
    form.classList.toggle('form-visible');
}

formButton.addEventListener('click', e => {
    const obj = {};
    const inputs = Array.from(document.querySelectorAll('form input'));
    inputs.forEach(input => {
        obj[input.name] = input.value;
    })
    books.push(obj);
    inputs.forEach(input => {
        input.value = '';
    })
    toggleForm();
    createBooks();
})

function createBooks() {
    const bookDiv = document.createElement('div');
    bookDiv.className = 'book';
    const bookIndex = books.length-1;
    // 遍历生成书籍属性
    for (const key in books[bookIndex]) {
        const bookGrid = document.createElement('div');
        bookGrid.className = 'book-grid';
        const h3 = document.createElement('h1');
        h3.textContent = `${key}:`;
        const p = document.createElement('h2');
        p.textContent = books[bookIndex][key];
        h3.className = 'long';
        p.className = 'long';
        bookGrid.append(h3, p);
        bookDiv.appendChild(bookGrid);
    }
    // 循环外生成单个删除按钮
    const btn = document.createElement('button');
    btn.style.top = '0.3rem';
    btn.style.right = '.5rem';  
    btn.style.position= 'absolute';
    btn.textContent = 'Delete';
    btn.className = 'button-1 delete-btn';
    btn.style.fontSize = '1rem';
    btn.setAttribute('data-key', `${bookIndex}`);
    bookDiv.appendChild(btn);

    bookDiv.setAttribute('id', `${bookIndex}`);
    bookDiv.style.position='relative';
    content.appendChild(bookDiv);

    // 仅给当前新生成的按钮绑定单次删除事件
    btn.addEventListener('click', () => {
        const targetKey = parseInt(btn.getAttribute('data-key'));
        const targetNode = document.getElementById(targetKey);
        if (targetNode) {
            content.removeChild(targetNode);
            books.splice(targetKey, 1); // 同步删除数组内对应数据,避免索引错乱
        }
    })
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 12:39:15