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

使用insertAdjacentHTML插入元素后无法选中及绑定事件的问题

问题原因

你遇到的问题是异步执行顺序导致的:getData()是异步函数,发起API请求后会继续执行后续代码,而document.querySelectorAll(".btn")在元素还没通过insertAdjacentHTML插入DOM时就运行了,所以拿到的是空NodeList,无法绑定事件。

解决方案

有两种常用的解决方式:

方式1:事件委托(推荐)

利用事件冒泡机制,把点击事件监听器绑定到已存在的父元素(比如.container)上,这样不管按钮什么时候动态插入,点击事件都会被父元素捕获并处理。

修改后的JS代码:

'use strict';
const quesContainer = document.querySelector('.container');

const renderData = function(mainTitle, quesTitle, tags, link1, link2, ytlink) {
  const html = `<button class="btn">hi</button>
      <div class="panel">
        <div class="topic">
          <div class="question">
            <p>
                <div class="mainTitle"><h1>${mainTitle}</h1></div>
                <div class="ques-title">${quesTitle}</div>
                <div class="link-1"><a href="${link1}">${link1}</a></div>
                <div class="link-2"><a href="${link2}">${link2}</a></div>
                <div class="tags">${tags}</div>
                <div class="yt-link"><a href="${ytlink}">Youtube Reference</a></div>
            </p>
          </div>
        </div>
      </div><br><br>`;
  quesContainer.insertAdjacentHTML('beforeend', html);
};

const getData = async function() {
  const data = await fetch("https://test-data-gules.vercel.app/data.json");
  const res = await data.json();
  const finalData = res.data;
  finalData.forEach(element => {
    element.ques.forEach(function(el) {
      renderData(element.title, el.title, el.tags, el.p1_link, el.p2_link, el.yt_link);
    })
  });
}

getData();

// 使用事件委托绑定点击事件
quesContainer.addEventListener('click', function(e) {
  // 确认点击的是.btn元素
  if (e.target.classList.contains('btn')) {
    const btn = e.target;
    console.log("clicked");
    btn.classList.toggle("active");
    const panel = btn.nextElementSibling;
    if (panel.style.maxHeight) {
      panel.style.maxHeight = null;
    } else {
      panel.style.maxHeight = panel.scrollHeight + "px";
    }
  }
});

方式2:在数据渲染完成后绑定事件

把获取按钮和绑定事件的代码放在getData()函数内部,等所有元素都插入DOM后再执行:

修改后的JS代码:

'use strict';
const quesContainer = document.querySelector('.container');

const renderData = function(mainTitle, quesTitle, tags, link1, link2, ytlink) {
  const html = `<button class="btn">hi</button>
      <div class="panel">
        <div class="topic">
          <div class="question">
            <p>
                <div class="mainTitle"><h1>${mainTitle}</h1></div>
                <div class="ques-title">${quesTitle}</div>
                <div class="link-1"><a href="${link1}">${link1}</a></div>
                <div class="link-2"><a href="${link2}">${link2}</a></div>
                <div class="tags">${tags}</div>
                <div class="yt-link"><a href="${ytlink}">Youtube Reference</a></div>
            </p>
          </div>
        </div>
      </div><br><br>`;
  quesContainer.insertAdjacentHTML('beforeend', html);
};

const getData = async function() {
  const data = await fetch("https://test-data-gules.vercel.app/data.json");
  const res = await data.json();
  const finalData = res.data;
  finalData.forEach(element => {
    element.ques.forEach(function(el) {
      renderData(element.title, el.title, el.tags, el.p1_link, el.p2_link, el.yt_link);
    })
  });

  // 所有元素渲染完成后再获取按钮并绑定事件
  const btns = document.querySelectorAll(".btn");
  console.log(btns);
  btns.forEach(function(element) {
    element.addEventListener("click", function() {
      console.log("clicked");
      element.classList.toggle("active");
      var panel = element.nextElementSibling;
      if (panel.style.maxHeight) {
        panel.style.maxHeight = null;
      } else {
        panel.style.maxHeight = panel.scrollHeight + "px";
      }
    });
  })
}

getData();

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 04:53:19