页面加载时获取视频真实宽高、宽高比和总时长,需设 preload="metadata" 并监听 loadedmetadata 事件读取 video.videowidth、video.videoheight 和 video.duration。

要在页面加载阶段就拿到视频的真实宽高、宽高比和总时长,核心是两步:用 preload="metadata" 触发元数据请求,再在 loadedmetadata 事件中读取 video.videoWidth、video.videoHeight 和 video.duration —— 这个时机最稳定,早于播放、也避开缓存导致的事件丢失风险。
为什么必须用 preload="metadata"?
这个属性告诉浏览器只拉取视频文件头部(比如 MP4 的 moov box),不下载画面帧数据。这样既能快速获得尺寸、时长、编码格式等关键信息,又节省带宽。若设为 none,首次点击播放才开始请求元数据,控件时间轴会延迟渲染;设为 auto 在 iOS Safari 上实际被忽略,等同于 none。
- 确保服务器支持字节范围请求(响应头含
Accept-Ranges: bytes),否则 metadata 模式可能退化为下载整个文件前几 KB - 对 MP4 文件,建议用
ffmpeg -c copy -movflags +faststart把 moov box 移到开头,避免因位置靠后导致 duration 读不出来 - 动态插入的
<video></video>元素即使写了preload="metadata",也不会自动触发预加载,需手动调用load()
监听 loadedmetadata 才能安全读取
这个事件只触发一次,在元数据解析完成时立即发生,比 canplay 或 loadeddata 更早、更可靠。直接访问 video.duration 或 video.videoWidth 极大概率得到 NaN 或 0,因为此时数据还没就绪。
- 绑定事件要尽早:最好在设置
src后立刻添加监听,而不是等到DOMContentLoaded,否则缓存资源可能已触发事件却无人接收 - 读取宽高时用
video.videoWidth / video.videoHeight计算宽高比,结果保留小数(如1.777),不要四舍五入成整数 - 时长需判断有效性:
if (isFinite(video.duration)) { /* 可用 */ },因为 HLS/DASH 流媒体或 moov 未就位的 MP4 可能返回Infinity或NaN
常见问题与绕过方案
如果 loadedmetadata 没触发,或 duration 始终为 NaN,别急着改 JS 逻辑,先排查底层原因:
- iOS Safari 下
preload被强制禁用,可配合<link rel="preload" as="video">主动发起请求(仅限同域) - 用户开启了低电量模式或省流量设置,Chrome/Firefox 会降级为
metadata甚至跳过缓冲 - 监听
durationchange作为兜底:当服务端延迟返回时长,该事件会在duration更新时再次触发 - 对本地文件(File API 场景),用
FileReader读取后赋值给video.src,同样需要重新绑定loadedmetadata
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











