我正在创建一个复杂的项目:一个Youtube UI克隆,我有一个JS的问题
理念
其思想是:在滚动条上会自动创建更多的div,类似于第一个div(工作正常)
问题
但是当我想为click
放置一个事件侦听器时,JavaScript并不处理后续div上的事件,但实际上,会自动生成50 ~ 100个其他div(具有相同的类),所以我认为.length
有问题
这里是一个网站,可以让你了解这个问题:
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
,它会执行click
函数,但是生成的div不能执行click
。我不知道是DOM没有更新还是我应该写更多的东西?在互联网上没有解决这个问题的结果(我希望能找到有经验的人,谁可以帮助我在这里)
3条答案
按热度按时间j7dteeu81#
您的问题是,您在页面加载时初始添加事件侦听器。这意味着添加事件侦听器的
for
循环将仅循环页面初始加载时存在的video-container
元素。添加事件侦听器后创建的任何video-container
元素都不会附加事件侦听器。即使你在一个元素上使用.cloneNode()
,这个元素有一个附加了addEventListener()
的事件监听器,这个事件监听器也不会被复制到新的元素上,因为addEventListener()
事件处理程序不会被复制。一个想法是在每次调用
createVideo()
时为videoComponent
添加一个新的事件侦听器。这样做的问题是,这可能会导致您向页面添加 * 许多 * 事件侦听器,这可能会降低网页的性能。更好的方法是使用event delegation。(在本例中为
<main>
元素)。当嵌套在父<main>
元素下的video-container
元素之一被单击时,单击事件将“冒泡”到<main>
元素,触发父<main>
元素上的click事件监听器。在附加到父<main>
元素的事件监听器中,可以使用e.target
获取对最初单击的video-container
元素的引用,其中e
是事件侦听器回调函数中提供的Event对象。由于单击事件侦听器位于父main
容器上,因此任何新创建的子元素的单击事件侦听器都将工作,因为来自子元素的事件将冒泡到父主容器的事件处理程序。要在代码中实现事件委托,您可以删除添加单个事件侦听器的
for
循环,并将单击事件侦听器添加到mainContainer
元素。这将捕获单击其子元素时冒泡的单击事件:这里我们还检查了clicked元素(
e.target
)实际上是一个视频容器元素,通过查看它是否是matches()
选择器.video-container
。这是必要的,因为我们的mainContainer
事件侦听器可以触发任何从它的任何子元素、孙元素等冒泡到它的点击事件。正如@Dai的评论中所指出的,在添加滚动事件侦听器时,您可能还需要考虑使用
passive
选项来提高性能。tpgth1q72#
简介
当你调用
addEventListener
时,只有已经存在的标签会接收到这个事件。未来的标签如果还不存在,就不会有这个事件。你需要以某种方式保证未来的元素也会有这个事件。你可以使用多种方法来实现这一点。onclick
保证
click
事件得到处理的一个非常简单的方法是为标记指定一个onclick
属性,如onclick="yourfunction
示例:
动态添加事件监听器
还可以以某种方式标记已经被初始化的项,并且随后仅将事件添加到尚未初始化的项,并且随后初始化它们。
示例:
一个二个一个一个
为HTML节点添加事件监听器
你可以直接调用
videoComponent.addEventListener
。示例:
突变观察器
图片来源:Mutation Observer for creating new elements
你可以使用Mutation Observer来检测标签的创建并将事件附加到标签上。如果可能的话,应该避免这样做,通常你有一个更简单的解决方案,但是,为了完整起见,这里有一个从上面分享的链接中提取的例子:
事件委托
最后,但并非最不重要的是,正如其他人已经提到的,您可以将事件委托给父节点,但在这种情况下,您需要找出事件的发起者是什么,即事件对象的
target
字段。示例:
dtcbnfnu3#
除了@Nick的回答之外,是的,可以用vanilla JS来做,但是如果JQuery可用,它会变得超级简单,可读性更强。
第一个参数是事件类型(点击,悬停等)。您可以使用任何传统的选择器作为第二个参数。