如何在window.onhashchange时停止YouTube视频?附实现代码
解决hash变化时停止YouTube视频播放的问题
这个场景在单页应用里太常见了——切换视图后视频还在后台播放,体验感很差。咱们可以借助YouTube iframe的postMessage API来控制播放状态,结合hashchange事件就能完美解决,具体方案如下:
核心思路
当URL的hash值发生变化时,找到所有正在播放的YouTube iframe,通过跨域消息传递向它们发送stopVideo命令,强制停止播放。如果需要的话,还可以把视频容器恢复成初始的封面占位图状态。
具体实现代码
你可以在现有代码基础上,添加这段hash监听逻辑:
// 监听hash变化事件 window.addEventListener('hashchange', function() { // 找到所有YouTube视频容器 const youtubeContainers = document.querySelectorAll('.youtube'); youtubeContainers.forEach(container => { const iframe = container.querySelector('iframe'); if (iframe) { // 向YouTube iframe发送停止播放命令 iframe.contentWindow.postMessage( JSON.stringify({ event: 'command', func: 'stopVideo', args: '' }), 'https://www.youtube.com' ); // 可选:恢复成初始的封面占位图 const embedId = container.dataset.embed; const source = `https://img.youtube.com/vi/${embedId}/hqdefault.jpg`; const image = new Image(); image.src = source; image.addEventListener('load', function() { container.innerHTML = ''; container.appendChild(image); }); } }); });
细节说明
- 安全的跨域消息传递:指定
'https://www.youtube.com'作为消息目标源,是为了符合浏览器的跨域安全策略,避免向无关域名发送消息。 - 恢复占位图:如果希望切换视图后,视频容器回到初始状态,上面代码里的“恢复封面图”部分可以保留,让用户下次点击时仍能看到封面再播放。
- 原代码小修正:我注意到你原代码里的load事件绑定有个小问题——原来的
image.addEventListener('load', function() {...}(i));写法会导致所有事件都指向最后一个元素,我在下面的完整整合代码里已经修正了这个问题,用立即执行函数正确绑定索引值。
完整整合代码
把初始化逻辑和hash监听逻辑放在一起,完整代码如下:
// 初始化YouTube视频占位图与点击播放逻辑 const youtube = document.querySelectorAll('.youtube'); for (let i = 0; i < youtube.length; i++) { const source = `https://img.youtube.com/vi/${youtube[i].dataset.embed}/hqdefault.jpg`; const image = new Image(); image.src = source; // 用立即执行函数正确绑定索引,避免闭包陷阱 (function(index) { image.addEventListener('load', function() { youtube[index].appendChild(image); }); })(i); youtube[i].addEventListener('click', function() { const iframe = document.createElement('iframe'); iframe.setAttribute('frameborder', '0'); iframe.setAttribute('allowfullscreen', ''); iframe.setAttribute('src', `https://www.youtube.com/embed/${this.dataset.embed}?rel=0&showinfo=0&autoplay=1`); this.innerHTML = ''; this.appendChild(iframe); }); } // hash变化时停止视频并恢复占位图 window.addEventListener('hashchange', function() { const youtubeContainers = document.querySelectorAll('.youtube'); youtubeContainers.forEach(container => { const iframe = container.querySelector('iframe'); if (iframe) { iframe.contentWindow.postMessage( JSON.stringify({ event: 'command', func: 'stopVideo', args: '' }), 'https://www.youtube.com' ); // 恢复封面占位图 const embedId = container.dataset.embed; const source = `https://img.youtube.com/vi/${embedId}/hqdefault.jpg`; const image = new Image(); image.src = source; image.addEventListener('load', function() { container.innerHTML = ''; container.appendChild(image); }); } }); });
内容的提问来源于stack exchange,提问作者DevWizard
相关产品推荐
相关产品推荐

