使用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,模拟移动端环境)
问题原因
- 事件绑定时机错误:在调用
createTags()创建DOM元素之前,就获取了.Content元素列表,此时新元素还未被添加到页面,绑定事件的操作仅对之前已存在的元素生效。每次循环时,只能绑定到之前创建的元素,最后一个元素创建后未被重新获取并绑定事件。 - 冗余循环逻辑:在
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
相关产品推荐
相关产品推荐

