这是我参与更文挑战的第13天,活动详情查看: 更文挑战
Custom HTML5 Video Player
这个模块一看标题就知道了,是要实现一个自定义的 HTML5 视频播放器,根据原作者的最终代码展示,可以看出,最终的效果里要实现视频的进度条可以控制,点击画面可以进行暂停/播放,左边的控制条为声音控制,右边的控制条为倍速控制。
一、效果展示
1.index-START.html
就是一个样式效果,先替你实现好了,默认运行就是这样效果。
2.index-FINISHED.html
将代码中的默认 JS 文件换成 带后缀完成标识的 JS 文件。
二、实现
最终代码
/* 获取元素 */
const player = document.querySelector('.player');
const video = player.querySelector('.viewer');
const progress = player.querySelector('.progress');
const progressBar = player.querySelector('.progress__filled');
const toggle = player.querySelector('.toggle');
const skipButtons = player.querySelectorAll('.skip');
const ranges = player.querySelectorAll('.player__slider');
function togglePlay() {
const method = video.paused ? 'play' : 'pause';
video[method]();
}
function updateButton() {
const icon = this.paused ? '►' : '❚ ❚';
console.log(icon);
toggle.textContent = icon;
}
function skip() {
video.currentTime += parseFloat(this.dataset.skip);
}
function handleRangeUpdate() {
//volume, playbackRate
video[this.name] = this.value;
}
function handleProgress() {
//currentTime 当前时间
//duration 总时间
//flexBasis 预设宽度
const percent = (video.currentTime / video.duration) * 100;
progressBar.style.flexBasis = `${percent}%`;
}
function scrub(e) {
const scrubTime = (e.offsetX / progress.offsetWidth) * video.duration;
video.currentTime = scrubTime;
}
/* Hook up the event listeners */
video.addEventListener('click', togglePlay);
toggle.addEventListener('click', togglePlay);
video.addEventListener('play', updateButton);
video.addEventListener('pause', updateButton);
video.addEventListener('timeupdate', handleProgress);
skipButtons.forEach(button => button.addEventListener('click', skip));
ranges.forEach(range => range.addEventListener('change', handleRangeUpdate));
ranges.forEach(range => range.addEventListener('mousemove', handleRangeUpdate));
let mousedown = false;
progress.addEventListener('click', scrub);
progress.addEventListener('mousemove', (e) => mousedown && scrub(e));
progress.addEventListener('mousedown', () => mousedown = true);
progress.addEventListener('mouseup', () => mousedown = false);
三、总结回顾
这个模块属于一个比较轻松的模块。
首先我们 video 标签那里加一个 controls 的属性,这时候我们就会发现,其实我们这个属性已经自带了一些控制的页面属性。
<video class="player__video viewer" src="652333414.mp4" controls></video>
当然原作者的效果更偏向于对于知识点和技术的练习,各自甄选进行学习。
原作者的这部分内容写的已经很好了,主要以分析理解为主,再复写一遍没有太大的意义。
过程分解
- 获取元素
/*进行了一些微调,主要看个人使用习惯*/
<button data-skip="-10" class="player__button skip">« 10s</button>
<button data-skip="25" class="player__button skip">25s »</button>
/* 获取元素 */
const player = document.querySelector('.player');
const video = player.querySelector('.viewer');
const progress = player.querySelector('.progress');
const progressBar = player.querySelector('.progress__filled');
const toggle = player.querySelector('.toggle');
const skipButtons = player.querySelectorAll('.skip');
const ranges = player.querySelectorAll('.player__slider');
- 相关事件 (1)播放/暂停
function togglePlay() {
const method = video.paused ? 'play' : 'pause';
video[method]();
}
这里使用了三元运算符,就省去了 if...else 这样比较冗杂的写法。
第二个比较有意思比较新颖的是 video[method]() 这样的写法。
(2)播放/暂停时,按钮的改变
function updateButton() {
const icon = this.paused ? '►' : '❚ ❚';
console.log(icon);
toggle.textContent = icon;
}
但是这样我就产生了疑问,之前要是类似这种的,肯定就在一个事件里去写了,如果拆分成两个事件的话,那么怎么串起来呢?
(3)事件串联
/* Hook up the event listeners */
video.addEventListener('click', togglePlay);
toggle.addEventListener('click', togglePlay);
video.addEventListener('play', updateButton);
video.addEventListener('pause', updateButton);
不得不说,我对这种写法感觉比较新奇。他是这样做的,当你点击的时候,会调用 togglePlay() 的 play() 和 pause() 方法,顺便在调用这两个方法的时候去改变按钮的切换。
哇,学到了学到了!!
(4)画面前进/后退
function skip() {
video.currentTime += parseFloat(this.dataset.skip);
}
skipButtons.forEach(button => button.addEventListener('click', skip));
(5)音量和播放速度的事件绑定
function handleRangeUpdate() {
//volume, playbackRate
video[this.name] = this.value;
}
ranges.forEach(range => range.addEventListener('change', handleRangeUpdate));
ranges.forEach(range => range.addEventListener('mousemove', handleRangeUpdate));
以前可能会用 video.volume 和 video.playbackRate 去取值,现在使用中括号就可以直接实现,省去了很多的步骤。 (6)画面拖动播放
function handleProgress() {
//currentTime 当前时间
//duration 总时间
//flexBasis 预设宽度
const percent = (video.currentTime / video.duration) * 100;
progressBar.style.flexBasis = `${percent}%`;
}
(7)画面点击播放对应时间
function scrub(e) {
const scrubTime = (e.offsetX / progress.offsetWidth) * video.duration;
video.currentTime = scrubTime;
}
let mousedown = false;
progress.addEventListener('click', scrub);
progress.addEventListener('mousemove', (e) => mousedown && scrub(e));
progress.addEventListener('mousedown', () => mousedown = true);
progress.addEventListener('mouseup', () => mousedown = false);
最后不要忘记了进度条的更新!!!
video.addEventListener('timeupdate', handleProgress);
不然就会是这个样子!!
四、重难点
首先自动检索相关学习知识点:
developer.mozilla.org/zh-CN/docs/…
developer.mozilla.org/zh-CN/docs/…
其实如果吸收了这两个部分的内容,今天这个模块理解起来就非常容易。
此外就是原作者在里边增加了一些比较新奇的写法,对于编程的思路和风格都是一个非常好的引导的指向标。