知识点/事件

1
<video src="bg.mp4" controls width="400" autoplay muted loop height="300" id="video"></video>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
var video = document.getElementById('video')

// 1、loadstart:视频查找。当浏览器开始寻找指定的音频/视频时触发,也就是当加载过程开始时
video.addEventListener('loadstart', function(e) {
console.log('提示视频的元数据已加载')
console.log(e)
console.log(video.duration) // NaN
})

// 2、durationchange:时长变化。当指定的音频/视频的时长数据发生变化时触发,加载后,时长由 NaN 变为音频/视频的实际时长
video.addEventListener('durationchange', function(e) {
console.log('提示视频的时长已改变')
console.log(e)
console.log(video.duration) // 528.981333 视频的实际时长(单位:秒)
})

// 3、loadedmetadata :元数据加载。当指定的音频/视频的元数据已加载时触发,元数据包括:时长、尺寸(仅视频)以及文本轨道
video.addEventListener('loadedmetadata', function(e) {
console.log('提示视频的元数据已加载')
console.log(e)
})

// 4、loadeddata:视频下载监听。当当前帧的数据已加载,但没有足够的数据来播放指定音频/视频的下一帧时触发
video.addEventListener('loadeddata', function(e) {
console.log('提示当前帧的数据是可用的')
console.log(e)
})

// 5、progress:浏览器下载监听。当浏览器正在下载指定的音频/视频时触发
video.addEventListener('progress', function(e) {
console.log('提示视频正在下载中')
console.log(e)
})

// 6、canplay:可播放监听。当浏览器能够开始播放指定的音频/视频时触发
video.addEventListener('canplay', function(e) {
console.log('提示该视频已准备好开始播放')
console.log(e)
})

// 7、canplaythrough:可流畅播放。当浏览器预计能够在不停下来进行缓冲的情况下持续播放指定的音频/视频时触发
video.addEventListener('canplaythrough', function(e) {
console.log('提示视频能够不停顿地一直播放')
console.log(e)
})

// 8、play:播放监听
video.addEventListener('play', function(e) {
console.log('提示该视频正在播放中')
console.log(e)
})

// 9、pause:暂停监听
video.addEventListener('pause', function(e) {
console.log('暂停播放')
console.log(e)
})

// 10、seeking:查找开始。当用户开始移动/跳跃到音频/视频中新的位置时触发
video.addEventListener('seeking', function(e) {
console.log('开始移动进度条')
console.log(e)
})

// 11、seeked:查找结束。当用户已经移动/跳跃到视频中新的位置时触发
video.addEventListener('seeked', function(e) {
console.log('进度条已经移动到了新的位置')
console.log(e)
})

// 12、waiting:视频加载等待。当视频由于需要缓冲下一帧而停止,等待时触发
video.addEventListener('waiting', function(e) {
console.log('视频加载等待')
console.log(e)
})

// 13、playing:当视频在已因缓冲而暂停或停止后已就绪时触发
video.addEventListener('playing', function(e) {
console.log('playing')
console.log(e)
})

// 14、timeupdate:目前的播放位置已更改时,播放时间更新
video.addEventListener('timeupdate', function(e) {
console.log('timeupdate')
console.log(e)
})

// 15、ended:播放结束
video.addEventListener('ended', function(e) {
console.log('视频播放完了')
console.log(e)
})

// 16、error:播放错误
video.addEventListener('error', function(e) {
console.log('视频出错了')
console.log(e)
})

// 17、volumechange:当音量更改时
video.addEventListener('volumechange', function(e) {
console.log('volumechange')
console.log(e)
})

// 18、stalled:当浏览器尝试获取媒体数据,但数据不可用时
video.addEventListener('stalled', function(e) {
console.log('stalled')
console.log(e)
})

// 19、ratechange:当视频的播放速度已更改时
video.addEventListener('ratechange', function(e) {
console.log('ratechange')
console.log(e)
})


实际应用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* 上面`timeupdate`方式较卡顿
* requestAnimationFrame能达到无缝渲染
* MDN https://developer.mozilla.org/zh-CN/docs/Web/API/Window/requestAnimationFrame
*/
let video = document.getElementById('video')
let canvas = document.getElementById('canvas')
let ctx = this.canvas.getContext('2d')
let rafId = null;

const drawVideo = () => {
if (video.ended) {
cancelAnimationFrame(rafId)
return;
}
ctx.clearRect(0, 0, canvas.width, canvas.height)
ctx.drawImage(video, 0, 0, canvas.width, canvas.height)
rafId = window.requestAnimationFrame(drawVideo)
}
window.requestAnimationFrame(drawVideo)

requestAnimationFrame刷新率不同保证运行速度一致

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
let lastTime = 0; // 上一次的时间戳

function animate(currentTime) {
if (!lastTime) lastTime = currentTime; // 初始化 lastTime

const deltaTime = currentTime - lastTime; // 计算两帧之间的时间差(毫秒)
lastTime = currentTime;

const speed = 0.1; // 每毫秒移动的速度
const distance = deltaTime * speed; // 根据时间差计算移动距离

// 更新动画位置
const element = document.getElementById('box');
element.style.transform = `translateX(${distance}px)`;

requestAnimationFrame(animate);
}

// 开始动画
requestAnimationFrame(animate);