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

EPC住宅能效查询应用:详情按钮重复绑定与模态框实现问题

问题:EPC应用中“查看详情”按钮事件重复绑定

开发一款获取住宅EPC(能源效率)数据的应用,通过地址或邮编搜索栏获取数据并以卡片形式展示,但点击“查看详情”按钮时,出现事件重复绑定问题——第一个按钮绑定1个事件,第二个按钮绑定2个事件,第三个按钮绑定3个事件,以此类推。

解决方案

原因分析

每次执行搜索后,在循环生成卡片的过程中,若反复获取所有.modalBtn按钮并绑定事件,会导致已存在的旧按钮被重复绑定事件,新生成的按钮也会被多次绑定,最终出现事件触发次数递增的问题。


解决方法

方法1:事件委托(最推荐)

给父容器outputContainer绑定一次事件,利用事件冒泡机制处理所有按钮的点击,无需给每个按钮单独绑定,彻底避免重复绑定问题。

步骤1:全局添加事件委托

在代码最外层(不要放在搜索函数或循环里)添加这段代码:

// 全局只绑定一次事件委托
outputContainer.addEventListener('click', async (e) => {
  // 判断点击的元素是详情按钮
  if (e.target.classList.contains('modalBtn')) {
    // 从卡片中提取对应地址(根据你的DOM结构调整选择器)
    const card = e.target.closest('.cards');
    const targetAddress = card.querySelector('.card-content').textContent;
    
    // 调用API获取完整详情数据
    const apiKey = "Basic 你的API密钥==";
    const endPoint = `https://epc.opendatacommunities.org/api/v1/non-domestic/search?address=${encodeURIComponent(targetAddress)}`;
    
    try {
      const res = await fetch(endPoint, {
        method: 'GET',
        headers: {
          Accept: "application/json",
          Authorization: apiKey,
        }
      });
      const detailData = await res.json();
      
      // 这里编写模态框展示逻辑,比如把detailData渲染到模态框中
      console.log('详情数据:', detailData);
    } catch (error) {
      console.error('获取详情失败:', error);
    }
  }
});

步骤2:修改搜索函数的卡片生成逻辑

去掉循环中获取modalBtn的代码,只负责生成卡片:

rows.forEach(row => {
  const address = row.address;
  const propertyType = row['property-type'];

  const cards = `  
  <div class="cards">
    <div class="card-address">
      <p class="card-title">Address:</p>
      <p class="card-content">${address}</p>
    </div>
    <div class="line"></div>

    <div class="card-property-type">
      <p class="card-title">Property Type:</p>
      <p class="card-content">${propertyType}</p>
    </div>

    <button class="modalBtn">View Details</button>
  </div>`;

  outputContainer.insertAdjacentHTML('beforeend', cards);
});

方法2:创建DOM元素时直接绑定事件

不使用字符串拼接HTML,而是通过document.createElement手动创建元素,给每个按钮单独绑定事件,确保每个按钮只被绑定一次。

修改getAddress函数中的循环部分:

rows.forEach(row => {
  const address = row.address;
  const propertyType = row['property-type'];

  // 创建卡片容器
  const card = document.createElement('div');
  card.className = 'cards';
  
  // 地址模块
  const addressDiv = document.createElement('div');
  addressDiv.className = 'card-address';
  addressDiv.innerHTML = `<p class="card-title">Address:</p><p class="card-content">${address}</p>`;
  card.appendChild(addressDiv);
  
  // 分割线
  const line = document.createElement('div');
  line.className = 'line';
  card.appendChild(line);
  
  // 物业类型模块
  const typeDiv = document.createElement('div');
  typeDiv.className = 'card-property-type';
  typeDiv.innerHTML = `<p class="card-title">Property Type:</p><p class="card-content">${propertyType}</p>`;
  card.appendChild(typeDiv);
  
  // 创建详情按钮并绑定事件
  const modalBtn = document.createElement('button');
  modalBtn.className = 'modalBtn';
  modalBtn.textContent = 'View Details';
  
  // 每个按钮只绑定一次事件
  modalBtn.addEventListener('click', async () => {
    const apiKey = "Basic 你的API密钥==";
    const endPoint = `https://epc.opendatacommunities.org/api/v1/non-domestic/search?address=${encodeURIComponent(address)}`;
    
    try {
      const res = await fetch(endPoint, {
        method: 'GET',
        headers: {
          Accept: "application/json",
          Authorization: apiKey,
        }
      });
      const detailData = await res.json();
      console.log('详情数据:', detailData);
      // 模态框展示逻辑
    } catch (error) {
      console.error('获取详情失败:', error);
    }
  });
  
  card.appendChild(modalBtn);
  outputContainer.appendChild(card);
});

方法3:清空容器再添加(不推荐,会丢失历史搜索结果)

如果不需要保留之前的搜索结果,可以在每次搜索前清空outputContainer,旧按钮被移除后就不会被重复绑定:

const getAddress = async (e) => {
  e.preventDefault();
  
  // 清空容器,移除所有旧卡片和按钮
  outputContainer.innerHTML = '';
  
  // 后续的API请求和卡片生成代码...
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 04:18:12