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

使用for循环绑定onclick事件时最后一个元素点击无响应求助

问题:点击视频元素时最后一个无响应

我要实现点击视频缩略图或标题弹出对应videoID的功能(用alert暂时代替iframe逻辑),用for(let i = 0; i < elements.length; i++)遍历元素绑定onclick事件,大部分元素点击正常,但最后一个元素点击无响应。完整代码如下:

原代码

HTML

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>Page title</title>
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <script defer src="./app.js"></script>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
</head>

<body>
  <div id="Main">

  </div>
</body>

</html>

CSS

* {
  margin: 0;
  padding: 0;
  outline: none;
  box-sizing: border-box
}

#Main {
  display: flex;
  justify-content: center;
  width: 100%;
  flex-direction: column;
  margin-top: 10px;
  align-items: center;
}

.Content {
  width: 90%;
  background: white;
  display: flex;
  justify-content: center;
  flex-direction: column;
  margin-top: 10px;
  gap: 10px;
}

.Thumbnails {
  width: 100%;
  height: 161px;
  background: blue;
}

.Titles {
  width: 100%;
  height: 30%;
  background: red;
  overflow: hidden;
  padding: 8px;
}

img {
  width: 100%;
  height: 100%;
  background-repeat: no-repeat;
}

p {
  height: 20%;
  width: 100%;
  font-size: 16px;
  color: white;
  width: 100%;
  font-weight: bold;
  text-align: center;
}

input {
  position: absolute;
  width: 76%;
}

JavaScript

fetch('https://youtube.googleapis.com/youtube/v3/playlistItems?part=snippet&maxResults=25&playlistId=UUiNxeE13Z4zTZYG_0r3RStw&key=AIzaSyDL4P5BqSx4p-juYifPzaoNJ_8WAZSprc4')
  .then(res => res.json())
  .then(data => {
    JSON.stringify(data.items.forEach((el) => {
      var ChannelID = [el.snippet.resourceId.videoId];
      var Thumbnails = [el.snippet.thumbnails.medium.url];
      var Titles = [el.snippet.title];

      function createTags() {
        const Blogs = $('#Main');
        for (let i = 0; i < ChannelID.length; i++) {
          const Tags = `
                      <div class="Content">
                      <input value="">
                          <div class="Thumbnails">
                      <img src=""/>
                          </div>
                          <div class="Titles">
                      <p></p>
                          </div>      
                      </div>
                    `
          var VideoData = $(Tags);
          VideoData.find('input').attr("value", ChannelID[i]);
          VideoData.find('img').attr("src", Thumbnails[i]);
          VideoData.find('p').text(Titles[i]);
          Blogs.append(VideoData);
        }
      }
      var Cont = document.getElementsByClassName("Content")
      for (let i = 0; i < Cont.length; i++) {
        Cont[i].onclick = () => {
          let imageURL = Cont[i].querySelector("input").value;
          alert("You clicked this video that has a channel ID of:" + imageURL);
        }
      }
      createTags();
    }));
  });

(注:测试时建议将桌面端屏幕缩至500px,模拟移动端环境)


问题原因

  1. 事件绑定时机错误:在调用createTags()创建DOM元素之前,就获取了.Content元素列表,此时新元素还未被添加到页面,绑定事件的操作仅对之前已存在的元素生效。每次循环时,只能绑定到之前创建的元素,最后一个元素创建后未被重新获取并绑定事件。
  2. 冗余循环逻辑:在data.items.forEach内部,将单个视频数据包裹成数组(如ChannelID = [el.snippet.resourceId.videoId]),再嵌套for循环创建元素,完全没必要,多余的循环会导致逻辑混乱。

修复方案

方案1:创建元素时直接绑定事件(推荐)

在创建每个.Content元素的同时直接绑定点击事件,避免事后遍历绑定的时机问题:

fetch('https://youtube.googleapis.com/youtube/v3/playlistItems?part=snippet&maxResults=25&playlistId=UUiNxeE13Z4zTZYG_0r3RStw&key=AIzaSyDL4P5BqSx4p-juYifPzaoNJ_8WAZSprc4')
  .then(res => res.json())
  .then(data => {
    const Blogs = $('#Main');
    data.items.forEach((el) => {
      const videoId = el.snippet.resourceId.videoId;
      const thumbnailUrl = el.snippet.thumbnails.medium.url;
      const title = el.snippet.title;

      const tagStr = `
        <div class="Content">
          <input type="hidden" value="${videoId}">
          <div class="Thumbnails">
            <img src="${thumbnailUrl}" alt="${title}">
          </div>
          <div class="Titles">
            <p>${title}</p>
          </div>      
        </div>
      `;
      const videoData = $(tagStr);
      // 直接绑定点击事件
      videoData.click(function() {
        const videoId = $(this).find('input').val();
        alert("你点击的视频ID是:" + videoId);
      });
      Blogs.append(videoData);
    });
  });

方案2:事件委托(更高效,适合动态元素)

利用事件冒泡特性,给父元素#Main绑定一次事件,后续添加的子元素自动继承事件响应,无需逐个绑定:

fetch('https://youtube.googleapis.com/youtube/v3/playlistItems?part=snippet&maxResults=25&playlistId=UUiNxeE13Z4zTZYG_0r3RStw&key=AIzaSyDL4P5BqSx4p-juYifPzaoNJ_8WAZSprc4')
  .then(res => res.json())
  .then(data => {
    const Blogs = $('#Main');
    data.items.forEach((el) => {
      const videoId = el.snippet.resourceId.videoId;
      const thumbnailUrl = el.snippet.thumbnails.medium.url;
      const title = el.snippet.title;

      const tagStr = `
        <div class="Content">
          <input type="hidden" value="${videoId}">
          <div class="Thumbnails">
            <img src="${thumbnailUrl}" alt="${title}">
          </div>
          <div class="Titles">
            <p>${title}</p>
          </div>      
        </div>
      `;
      Blogs.append(tagStr);
    });
  });

// 事件委托:父元素监听子元素点击
$('#Main').on('click', '.Content', function() {
  const videoId = $(this).find('input').val();
  alert("你点击的视频ID是:" + videoId);
});

额外优化点

  • 将input改为type="hidden",避免原绝对定位导致的页面遮挡问题
  • 移除冗余的数组包裹,直接存储单个视频数据(无需将单个值放入数组)
  • 删除无用的JSON.stringify()调用,它对forEach的执行没有任何帮助

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 11:10:54