HTML媒体加载失败需分层应对:图片用onerror+data-loaded防死循环,视频依video.error.code分类处理并多source降级,所有资源须绕过file://协议限制,否则90%失败实为浏览器拦截。
HTML媒体加载失败没有“万能备用方案”,只有分层应对策略:图片靠onerror+data-loaded防死循环,视频靠video.error.code分类处理+多source降级,所有资源都必须绕过file://协议限制——否则90%的“失败”根本不是代码问题,而是浏览器主动拦截。
onerror为什么一写就卡死?因为备用图也404时会无限触发onerror,内存暴涨甚至页面崩溃。它不是“换一张图”那么简单,而是要切断事件链。
onerror="if (!this.dataset.loaded) { this.dataset.loaded = '1'; this.src = 'fallback.png'; }"——必须加dataset标记,不能只靠this.onerror = null
img元素,onerror必须在appendChild()前绑定,否则来不及捕获首次错误data:image/png;base64,...内联base64,彻底规避路径风险alt不是视觉替补,它只服务读屏器;空白区域要“看起来正常”,得靠onerror或CSS占位error事件怎么区分真实失败?video.error对象的code值才是关键信号,不是所有报错都该重试——比如MEDIA_ERR_DECODE(解码失败)重试毫无意义。
video.error.code === 2(MEDIA_ERR_NETWORK):可尝试fetch(video.currentSrc, { method: 'HEAD' })验证URL是否可达video.error.code === 4(MEDIA_ERR_SRC_NOT_SUPPORTED):说明所有source都不被支持,需检查canPlayType()返回值,而非盲目切换video.error.code === 3(MEDIA_ERR_DECODE):大概率是编码不兼容(如Safari不支持AV1),应降级到H.264 MP4,而不是换CDN地址error事件只在加载阶段触发,播放中卡顿、花屏、音画不同步不会触发它根本不是路径写错,是浏览器对file://协议的主动封锁:JS/CSS/图片请求被拦截,控制台报net::ERR_FILE_NOT_FOUND或Access to script at 'file:///xxx.js' from origin 'null'。
立即学习“前端免费学习笔记(深入)”;
ritwickdey.LiveServer插件,右键选Open with Live Server——这是唯一可靠开发方式--allow-file-access-from-files参数已逐步废弃,别依赖./video.mp4比video.mp4更稳,尤其在Webpack或Vite构建后路径可能被重写Blocked by CORS policy,onerror仍会触发,但换源无效——得换托管方式,不是前端能解决的error事件真能兜底吗?能,但必须精准过滤,否则会误伤脚本、样式表甚至XHR请求。
document.addEventListener('error', e => { if (e.target.tagName === 'IMG' && !e.target.dataset.handled) { ... } }, true)——第三个参数true表示捕获阶段,确保命中e.target.tagName判断类型,script和link的onerror行为与img不同,不能混用逻辑src为空、undefined或纯空格时,onerror根本不触发——这类问题得靠构建工具校验(如webpack的html-loader报Must be non-empty)srcset中的单个候选源失败,onerror也不响应,只能靠服务端统一返回适配格式最易被忽略的点:错误分类决定动作,不是所有失败都该“换源”。解码失败换CDN没用,网络失败重试三次就够了,格式不支持却硬塞WebM只会让iOS用户白屏——真正的鲁棒性,来自对每个video.error.code和img加载上下文的精确响应。