SvelteKit中onloadeddata行为异常问题排查
问题原因分析
你的代码核心问题出在事件绑定时机滞后和未覆盖缓存/快速加载场景:
- 开发模式下本地视频加载极快,
onMount执行时loadeddata事件已经触发完毕,此时再绑定事件自然捕获不到。 - 生产模式下,视频可能从浏览器缓存加载(事件触发更快)或网络加载(触发较慢),导致事件有时能捕获有时不能。
- 直接赋值
onloadeddata的方式无法处理事件已提前触发的情况,且未在组件销毁时解绑事件,存在内存泄漏风险。
修复方案
1. 提前检查视频加载状态,兼容已完成加载的场景
视频元素的readyState属性可判断当前加载进度:
readyState >= 2对应HAVE_CURRENT_DATA状态,即已触发loadeddata事件。
绑定事件前先检查该状态,若已满足则直接执行回调,无需等待事件触发。
2. 使用addEventListener绑定事件并在组件销毁时解绑
相比直接赋值onloadeddata,addEventListener更灵活,且能避免覆盖其他可能的事件监听;同时在组件销毁时移除监听,防止内存泄漏。
3. 补充视频初始样式
给视频添加初始透明样式,保证加载完成后显示的过渡效果正常。
修改后的完整代码
<script> import { onMount, onDestroy } from 'svelte' export let hdSrcArr = [], nonHdSrcArr = [] let refHd = null, refSmall = null, showLowQualityVideo = true // 低清视频加载完成回调 function handleSmallLoaded() { if (!refSmall) return refSmall.style.opacity = 1 refSmall.disablePictureInPicture = true } // 高清视频加载完成回调 function handleHdLoaded() { if (!refHd || !refSmall) return refHd.currentTime = refSmall.currentTime refHd.style.opacity = 1 refHd.disablePictureInPicture = true showLowQualityVideo = false } onMount(() => { // 处理低清视频 if (refSmall) { // 检查是否已加载完成 if (refSmall.readyState >= 2) { handleSmallLoaded() } else { refSmall.addEventListener('loadeddata', handleSmallLoaded) } } // 处理高清视频 if (refHd) { if (refHd.readyState >= 2) { handleHdLoaded() } else { refHd.addEventListener('loadeddata', handleHdLoaded) } } }) // 组件销毁时移除事件监听 onDestroy(() => { if (refSmall) { refSmall.removeEventListener('loadeddata', handleSmallLoaded) } if (refHd) { refHd.removeEventListener('loadeddata', handleHdLoaded) } }) </script> <style> video { opacity: 0; transition: opacity 0.3s ease; /* 让两个视频重叠显示,按需调整定位 */ position: absolute; top: 0; left: 0; width: 100%; height: 100%; } </style> {#if showLowQualityVideo} <video bind:this={refSmall} playsinline autoplay muted loop preload="auto" > {#each nonHdSrcArr as video} <source src={video.video} type={video.type} /> {/each} </video> {/if} <video bind:this={refHd} playsinline autoplay muted loop preload="auto" > {#each hdSrcArr as video} <source src={video.video} type={video.type} /> {/each} </video>
额外注意事项
- 两个视频需通过定位重叠,否则会同时显示;样式中已添加基础定位,可根据布局调整。
- 必须同时保留
autoplay和muted属性,符合浏览器自动播放策略,否则视频可能无法自动加载播放。 - 若视频资源较大,可监听
progress事件优化加载中的过渡体验。
内容的提问来源于stack exchange,提问作者Evgeny Alekseev
相关产品推荐
相关产品推荐

