场景
需要用视频的某一帧作为预览图
思路
创建video对象,加载视频元数据,然后用canvas绘制video的画面。
实现细节
1 创建video对象,加载元数据,然后监听必要事件
const getVideoFirstFrame = (videoUrl: string) => {
const video = document.createElement("video")
video.preload = "metadata"
video.src = videoUrl
video.addEventListener("loadedmetadata", () => {
// 设置视频时间到第1秒(取决于你想获取第几秒的画面)
video.currentTime = 1
})
// currentTime修改后,会触发seeked事件
video.addEventListener("seeked", () => {
}, { once: true }) // 只监听一次
}
2 创建canvas对象,然后绘制video画面
const getVideoFirstFrame = (videoUrl: string) => {
const video = document.createElement("video")
video.preload = "metadata"
video.src = videoUrl
video.addEventListener("loadedmetadata", () => {
// 设置视频时间到第1秒(取决于你想获取第几秒的画面)
video.currentTime = 1
})
// currentTime修改后,会触发seeked事件
video.addEventListener("seeked", () => {
const canvas = document.createElement("canvas")
canvas.width = video.videoWidth
canvas.height = video.videoHeight
const ctx = canvas.getContext("2d")
ctx?.drawImage(video, 0, 0)
// 转换为base64(这里已经获取到视频画面了)
const dataUrl = canvas.toDataURL("image/jpeg")
}, { once: true }) // 只监听一次
}
3 绘制操作是异步的,修改函数返回promise
const getVideoFirstFrame = (videoUrl: string) => {
return new Promise((resolve, reject) => {
const video = document.createElement("video")
video.preload = "metadata"
video.src = videoUrl
video.addEventListener("loadedmetadata", () => {
// 设置视频时间到第1秒(取决于你想获取第几秒的画面)
video.currentTime = 1
})
// currentTime修改后,会触发seeked事件
video.addEventListener("seeked", () => {
try {
const canvas = document.createElement("canvas")
canvas.width = video.videoWidth
canvas.height = video.videoHeight
const ctx = canvas.getContext("2d")
ctx?.drawImage(video, 0, 0)
// 转换为base64(这里已经获取到视频画面了)
const dataUrl = canvas.toDataURL("image/jpeg")
// 清理
video.remove()
canvas.remove()
resolve(dataUrl)
} catch (err) {
reject(err)
}
}, { once: true }) // 只监听一次
// 错误处理
video.addEventListener("error", (err) => {
reject(new Error(`视频加载失败: ${err}`))
})
})
}
4 调用
<script setup lang="ts">
onMounted(async () => {
const videoUrl = "https://vjs.zencdn.net/v/oceans.mp4"
const frame = await getVideoFirstFrame(videoUrl)
img.value = frame
})
</script>
<template>
<img v-if="img" :src="img" />
</template>
5 验证结果
注意事项
如果你的视频地址是跨域的,canvas将无法绘制视频内容
你需要做两件事:
1 让后台设置允许跨域的响应头
Access-Control-Allow-Origin: * 或指定具体域名
2 设置video.crossOrigin = "anonymous"
否则浏览器会报SecurityError错误:
SecurityError: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。