组件中鼠标悬停播放视频仅触发DOM内最后一个视频的问题求助
解决鼠标悬停仅最后一个视频播放的问题
嘿,这个问题我太熟了——这是典型的var变量作用域+闭包陷阱!咱们来拆解下问题原因,再给你几个靠谱的解决方案:
问题根源
你用var声明了循环里的vid变量,而var是函数级作用域,整个videoPlays函数里只有一个vid变量。循环执行时,每次迭代都会把vid重新赋值为当前视频元素,但所有的mouseover/mouseout回调函数都是异步触发的——等你真正把鼠标放到视频上时,循环早就跑完了,vid已经被赋值成最后一个视频元素,所以所有回调都会操作最后那个视频。
解决方案
方案1:用let替代var(最简洁)
let是ES6引入的块级作用域变量,每次循环迭代都会创建一个新的vid变量,每个回调函数都会绑定当前迭代的那个视频元素:
document.addEventListener("DOMContentLoaded", videoPlays, false); function videoPlays() { const videos: HTMLCollectionOf<Element> = document.getElementsByClassName("video"); for(let i = 0; i < videos.length ; i++) { // 把var改成let const vid: HTMLVideoElement = videos[i] as HTMLVideoElement; vid.addEventListener("mouseover", () => { vid.play(); }); vid.addEventListener("mouseout", () => { vid.pause(); }); } }
方案2:用forEach遍历(更优雅)
把HTMLCollection转成数组后用forEach遍历,每个回调函数都会拿到独立的视频元素引用,避免作用域问题:
document.addEventListener("DOMContentLoaded", videoPlays, false); function videoPlays() { // 把HTMLCollection转成数组 const videos = Array.from(document.getElementsByClassName("video")) as HTMLVideoElement[]; videos.forEach(vid => { vid.addEventListener("mouseover", () => vid.play()); vid.addEventListener("mouseout", () => vid.pause()); }); }
方案3:用闭包创建独立作用域(兼容老环境)
如果需要兼容不支持ES6的环境,可以用立即执行函数表达式(IIFE)创建闭包,把当前视频元素封装到独立作用域里:
document.addEventListener("DOMContentLoaded", videoPlays, false); function videoPlays() { var video: HTMLCollectionOf<Element> = document.getElementsByClassName("video"); for(var i = 0; i < video.length ; i++) { // 用IIFE把当前视频元素作为参数传入,创建独立作用域 (function(currentVid) { currentVid.addEventListener("mouseover", () => { currentVid.play(); }); currentVid.addEventListener("mouseout", () => { currentVid.pause(); }); })(video[i] as HTMLVideoElement); } }
问题演示
内容的提问来源于stack exchange,提问作者Bogomip
相关产品推荐
相关产品推荐

