如何为 JavaScript 生成的所有 div 放置一个 EventListener
Posted
技术标签:
【中文标题】如何为 JavaScript 生成的所有 div 放置一个 EventListener【英文标题】:how to put a EventListener for all divs generated by JavaScript 【发布时间】:2022-01-24 00:27:16 【问题描述】:我正在尝试创建一个复杂的项目:一个 youtube UI 克隆,我遇到了 js 问题
想法
这个想法是在滚动上自动创建更多的 div,类似于第一个(这很好)
问题
但是当我想放一个click的eventListener时,javascript认为html中只有一个div,
但实际上,自动生成了50~100个其他div(同一个类)
所以我认为.lenght
有问题
这里是让您了解问题的网站:
https://laaouatni.github.io/yt-clone/
我认为问题出在这里:
function createVideo()
let videoComponent = videoContainer.cloneNode(true);
mainContainer.appendChild(videoComponent);
...
<main>
<div class="video-container">
...
</div>
<!-- here javascript will put other divs on scroll -->
</main>
...
window.addEventListener("scroll", function()
let scrollPercentage = (window.scrollY / (document.body.scrollHeight - window.innerHeight)) * 100;
if (scrollPercentage > 70)
createVideo();
let videoContainer = document.querySelector(".video-container");
let allVideoContainer = document.querySelectorAll(".video-container");
for (let index = 0; index < allVideoContainer.length; index++)
allVideoContainer[index].addEventListener("click", function()
console.log("clicked video N " + index);
)
如果我单击手动编写的 div,它会执行单击功能,但是对于生成的 div,单击不起作用。我不知道是 DOM 没有更新还是我应该写更多的东西?在网上没有解决问题的结果(我希望找到有经验的人,可以在这里帮助我)
如果您需要,所有代码 github repo(帮助我们)
https://github.com/Laaouatni/yt-clone
【问题讨论】:
“一个 youtube UI 克隆” - 为什么? 您的scroll
事件监听器必须是 passive
。
@Dai passive
是什么意思? (我是初学者)
见***.com/questions/37721782/…
事件委托还可以解决动态创建的 div 没有附加事件侦听器的问题。 ***.com/questions/1687296/…
【参考方案1】:
您的问题是您最初是在页面加载时添加事件侦听器。这意味着添加事件侦听器的for
循环将仅遍历页面初始加载时出现的video-container
元素。添加事件侦听器后创建的任何video-container
元素都不会附加事件侦听器。即使您在带有addEventListener()
附加的事件侦听器的元素上使用.cloneNode()
,也不会将事件侦听器复制到新元素,因为不会复制addEventListener()
事件处理程序。
一个想法是在每次调用createVideo()
时向videoComponent
添加一个新的事件侦听器。这样做的问题是,这可能会导致您向页面添加 许多 事件侦听器,这会降低网页的性能。
一个更好的主意是使用event delegation。事件委托的想法是您可以将事件侦听器添加到一个父元素(在您的情况下为 <main>
元素)。当您单击嵌套在父<main>
元素下的video-container
元素之一时,单击事件将"bubble" up 发送到<main>
元素,触发父<main>
元素上的单击事件侦听器。在附加到父<main>
元素的事件监听器中,您可以使用e.target
获取对最初点击的video-container
元素的引用,其中e
是事件监听器回调函数中提供的Event对象。由于 click 事件侦听器位于父 main
容器上,因此任何新创建的子元素的 click 事件侦听器都将起作用,因为来自子元素的事件将冒泡到父主容器的事件处理程序。
要在您的代码中实现事件委托,您可以删除添加单个事件侦听器的for
循环,而是将您的点击事件侦听器添加到您的mainContainer
元素中。这将捕获单击其子级时冒泡的单击事件:
mainContainer.addEventListener("click", function(e) // e = event object
if (e.target && e.target.matches(".video-container"))
const clickedVideoContainer = e.target;
// do stuff with `clickedVideoContainer`
);
在这里,我们还检查被点击的元素 (e.target
) 实际上是一个视频容器元素,方法是查看它是否为matches()
选择器.video-container
。这是必需的,因为我们的 mainContainer
事件监听器可以触发任何从其子代、孙代等冒泡的点击事件。
正如@Dai 在 cmets 中所指出的,您可能还需要考虑在添加滚动事件侦听器时使用 passive
option 以提高性能。
【讨论】:
以上是关于如何为 JavaScript 生成的所有 div 放置一个 EventListener的主要内容,如果未能解决你的问题,请参考以下文章