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

JavaScript中动态创建的父元素事件可触发,子元素为何不行?

手风琴组件子元素事件绑定失效问题排查

问题场景

动态创建手风琴组件,要求同一时间仅展开一个项,点击标题触发展开/切换逻辑。为动态生成的标题div绑定click事件后无法触发,但为其父元素item绑定同一事件却能正常执行。

相关代码

function createInfo() {
    const info = document.querySelector('#info');

    const accordion = document.createElement('div');
    accordion('class', 'accordion'); // 注:此处应为accordion.setAttribute('class', 'accordion'),原代码存在语法错误

    const accordionItemList = [...];

    for (const itemObject of accordionItemList) {
        const item = document.createElement('div');
        item.setAttribute('class', 'accordion-item');

        const title = document.createElement('div');
        title.setAttribute('class', 'accordion-title');
        title.innerHTML = `<p>${itemObject.title}</p><div class="arrow">`;
        item.appendChild(title);

        item.innerHTML += `<div class="accordion-text">${itemObject.text}</div>`;

        accordion.appendChild(item);

        // 此事件无法触发
        title.addEventListener('click', () => {
            handleExpand(item, accordion.children);
        });

        // 此事件可正常触发
        item.addEventListener('click', () => {
            handleExpand(item, accordion.children);
        });
    }

    info.appendChild(accordion);
}

问题原因

核心问题出在item.innerHTML +=

${itemObject.text}
``这一行:

  • 当使用innerHTML +=时,浏览器会先将item当前的所有内容(包括已经通过appendChild添加的title元素)转换成HTML字符串,拼接上新内容后重新解析,生成全新的DOM节点替换掉item原来的子元素。
  • 原来绑定了事件的title元素被销毁,新生成的title节点是完全不同的DOM对象,之前绑定的click事件自然失效。
  • 而item元素本身是始终存在的DOM节点,没有被替换,因此它的事件绑定不受影响。

解决办法

有两种可行的修复方式:

方式一:先完成所有DOM拼接,再绑定事件

将事件绑定代码移到item.innerHTML +=之后,操作重新生成后的title节点:

for (const itemObject of accordionItemList) {
    const item = document.createElement('div');
    item.setAttribute('class', 'accordion-item');

    item.innerHTML = `<div class="accordion-title"><p>${itemObject.title}</p><div class="arrow"></div></div>` + 
                     `<div class="accordion-text">${itemObject.text}</div>`;

    accordion.appendChild(item);

    // 此时获取的是重新生成后的title节点
    const title = item.querySelector('.accordion-title');
    title.addEventListener('click', () => {
        handleExpand(item, accordion.children);
    });

    item.addEventListener('click', () => {
        handleExpand(item, accordion.children);
    });
}

方式二:用appendChild代替innerHTML +=添加文本区域

避免重新解析整个item的内容,保留原来的title节点:

for (const itemObject of accordionItemList) {
    const item = document.createElement('div');
    item.setAttribute('class', 'accordion-item');

    const title = document.createElement('div');
    title.setAttribute('class', 'accordion-title');
    title.innerHTML = `<p>${itemObject.title}</p><div class="arrow"></div>`;
    item.appendChild(title);

    // 用createElement和appendChild添加文本区域,不破坏原有DOM结构
    const textDiv = document.createElement('div');
    textDiv.setAttribute('class', 'accordion-text');
    textDiv.textContent = itemObject.text; // 若text含HTML则用innerHTML
    item.appendChild(textDiv);

    accordion.appendChild(item);

    // 此时title节点未被替换,事件绑定有效
    title.addEventListener('click', () => {
        handleExpand(item, accordion.children);
    });

    item.addEventListener('click', () => {
        handleExpand(item, accordion.children);
    });
}

另外注意原代码中accordion('class', 'accordion')是语法错误,应改为accordion.setAttribute('class', 'accordion')或accordion.className = 'accordion'。

内容的提问来源于stack exchange,提问作者Ahmet C. Buyukyilmaz

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 01:13:23