場景
需要用影片的某一幀作為預覽圖
思路
建立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.