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

使用eval创建动态变量与事件监听仅最后元素生效问题求助

问题原因
  1. innerHTML +=的DOM渲染缺陷:每次用innerHTML +=拼接内容时,浏览器会重新解析整个Layout_02的HTML结构,销毁原有DOM元素并重新创建,之前绑定的所有事件监听都会丢失。只有最后一次添加的元素,因为是新创建后立即绑定事件,所以能正常响应。
  2. eval()的滥用问题:用eval()动态创建变量不仅存在XSS安全风险,还会导致变量作用域混乱,箭头函数中引用的变量会因闭包问题指向最后一次循环的doc.id,进一步加剧事件绑定失效的情况。
解决方案

方案1:直接创建DOM元素并绑定事件(推荐,直观可控)

放弃innerHTML拼接,改用原生DOM API创建元素,逐个绑定事件后添加到容器中,避免原有DOM被销毁:

function Versiones(doc) {
  // 创建容器包裹单组版本信息
  const versionContainer = document.createElement('div');

  // 创建可点击的ID段落
  const idPara = document.createElement('p');
  idPara.id = doc.id;
  idPara.textContent = `Id= ${doc.id}`;
  // 直接绑定点击事件,传入当前doc对象
  idPara.addEventListener('click', () => Documento(doc));

  // 创建其他信息段落
  const otPara = document.createElement('p');
  otPara.textContent = `OT= ${doc.data().OT}`;

  const entregaPara = document.createElement('p');
  entregaPara.textContent = `Entrega= ${doc.data().Entrega.toDate().toDateString()}`;

  const registradoPara = document.createElement('p');
  registradoPara.textContent = `Registrado= ${doc.data().Generada.toDate().toDateString()}`;

  // 组装元素并添加到页面
  versionContainer.append(idPara, otPara, entregaPara, registradoPara);
  Layout_02.appendChild(versionContainer);
}

function Documento(doc) {
  console.log("Recibido: ");
  console.log(doc.id);
}

方案2:事件委托(适合大量元素,性能更优)

通过给父容器Layout_02绑定一次事件,利用事件冒泡机制处理所有子元素的点击,无需逐个绑定:

function Versiones(doc) {
  // 用insertAdjacentHTML添加内容,避免innerHTML +=导致的DOM重绘
  const versionHtml = `
    <div class="version-group">
      <p class="clickable-id" data-doc-id="${doc.id}">Id= ${doc.id}</p>
      <p>OT= ${doc.data().OT}</p>
      <p>Entrega= ${doc.data().Entrega.toDate().toDateString()}</p>
      <p>Registrado= ${doc.data().Generada.toDate().toDateString()}</p>
    </div>
  `;
  Layout_02.insertAdjacentHTML('beforeend', versionHtml);
}

// 页面初始化时绑定一次事件委托
Layout_02.addEventListener('click', (e) => {
  // 找到被点击的目标元素(支持点击子元素时向上匹配)
  const clickedIdPara = e.target.closest('.clickable-id');
  if (clickedIdPara) {
    const docId = clickedIdPara.dataset.docId;
    // 若需要完整doc对象,建议提前缓存所有Firebase返回的doc数据
    // 例如:const targetDoc = allDocs.find(doc => doc.id === docId);
    // Documento(targetDoc);
    console.log("Recibido: ", docId);
    // 若只需id,可修改Documento函数直接接收id参数
  }
});

function Documento(doc) {
  console.log("Recibido: ");
  console.log(doc.id);
}
关键优化点
  • 彻底抛弃innerHTML +=和eval(),改用更安全、可控的DOM操作方式
  • 事件委托减少事件绑定数量,提升性能,同时避免DOM重绘导致的事件丢失问题
  • 直接传递doc对象或利用dataset存储关键数据,避免通过id重复查询DOM

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 23:51:16