第十一天挑战(视频控制)
所有内容均上传至gitee,答案不唯一,仅代表本人思路
中文详解:https://github.com/soyaine/JavaScript30
该详解是Soyaine及其团队 整理编撰的,是对源代码的详解 ,强烈推荐大家观看学习!!!
本人gitee:https://gitee.com/thats-all-right-ha-ha/30-days---js-challenge
效果
-
样式分析
- 组件总共分两个部分,首先是视频主体部分
- 其次是控制部分,控制部分也分为两个部分,一个是视频进度条 另一个是视频控件
-
逻辑分析
-
点击视频后视频开始播放和暂停,并且下方控制按钮根据视频状态切换
-
进度条根据视频进度进行对应,拖动和点击进度条可以控制视频的进度
-
左侧range条可以控制音量的大小(点击或拖动)
-
右侧range条可以控制视频的倍速(点击或拖动)
-
右侧控件可以根据对应的值对视频进行快进或快退
-
本人代码及思路分析
仅提供布局及逻辑代码
结构:
html
<div class="player">
<video class="player__video viewer" src="652333414.mp4"></video>
<div class="player__controls">
<div class="progress">
<div class="progress__filled"></div>
</div>
<button class="player__button toggle" title="Toggle Play">►</button>
<input type="range" name="volume" class="player__slider" min="0" max="1" step="0.05" value="1">
<input type="range" name="playbackRate" class="player__slider" min="0.5" max="2" step="0.1" value="1">
<button data-skip="-10" class="player__button"><< 10s</button>
<button data-skip="25" class="player__button">25s >></button>
</div>
</div>
逻辑:
js
const player = document.querySelector('.player')
const toggle = document.querySelector('.toggle')
const volume = document.querySelector('[name="volume"]')
const playbackRate = document.querySelector('[name="playbackRate"]')
const skipButton = document.querySelectorAll('[data-skip]')
const view = document.querySelector('.viewer')
const progressFilled = document.querySelector('.progress__filled')
const progress = document.querySelector('.progress')
let isClick = false
//视频播放开关
function viewSwitch(){
view.paused ? view.play() : view.pause()
}
//播放图片切换
function iconChange() {
const icon = this.paused ? '►' : '❚ ❚';
toggle.textContent = icon
}
//视频快进/快退
function skip() {
console.log(view.currentTime)
view.currentTime += ~~this.dataset.skip
}
//视频倍速
function videoRate(e){
view.playbackRate = e.target.value
}
//添加声音
function videoVolume(e){
view.volume = e.target.value
}
//进度条
function progressBar(){
const nowLoding = view.currentTime / view.duration
progressFilled.style.flexBasis = `${nowLoding * 100}%`
}
//控制进度条
function changeProgressBar(e){
const nowWidth = e.offsetX / progress.offsetWidth
view.currentTime = view.duration * nowWidth
}
//视频控制
view.addEventListener('click',viewSwitch)
view.addEventListener('play', iconChange)
view.addEventListener('pause',iconChange)
view.addEventListener('timeupdate',progressBar)
//播放按钮控制
toggle.addEventListener('click',viewSwitch)
//快进快退
skipButton.forEach(element => {
element.addEventListener('click',skip)
});
//视频倍速
playbackRate.addEventListener('input',videoRate)
//视频音量
volume.addEventListener('input',videoVolume)
//拖动控制条
progress.addEventListener('click',changeProgressBar)
progress.addEventListener('mousedown', () => {
isClick = true
})
progress.addEventListener('mousemove', (e) => {
if(isClick){
changeProgressBar(e)
}
})
progress.addEventListener('mouseup', () => {
isClick = false
})
分析:
-
**整体思路:**获取所有需要添加事件的元素,并且添加事件,通过控制视频的属性来控制视频的播放,通过range的值更改视频的音量和倍速
-
具体实现:
- viewSwitch :通过paused 属性判断当前的视频播放状态(paused返回布尔值)
- iconChange :通过paused属性判断当前视频的播放状态,根据当前视频状态更改控件样式
- skip :通过currentTime 控制当前视频的进度,利用dataset获取标签上对应的自定义值,让其相加实现快进/快退效果(dataset标签上的值是字符类型,需要先进行转换)
- videoRate :获取range标签的值,通过playbackRate更改视频的倍速,
- videoVolume :获取range标签的值,通过volume更改视频的音量
- progressBar :通过currentTime 获取当前的时长,通过duration获取总视频的时长,让其相除,获取比例 *100更改进度条的百分比
- changeProgressBar :通过offsetX 获取当前鼠标点击的值,通过offsetWidth获取进度条总长度,让其相除获得比例,通过比例更改视频进度
- 监听视频的 点击 、开始 、暂停 、进度更改事件,并根据事件执行对应函数
-
弊端分析(与官方方法对比):
- mousemove事件仅作用于进度条内,如果移动的过程中鼠标脱离出了该范围,则会失效
官方代码
官方代码仅代表该案例原作者思路,不唯一
结构
html
<div class="player">
<video class="player__video viewer" src="652333414.mp4"></video>
<div class="player__controls">
<div class="progress">
<div class="progress__filled"></div>
</div>
<button class="player__button toggle" title="Toggle Play">►</button>
<input type="range" name="volume" class="player__slider" min="0" max="1" step="0.05" value="1">
<input type="range" name="playbackRate" class="player__slider" min="0.5" max="2" step="0.1" value="1">
<button data-skip="-10" class="player__button"><< 10s</button>
<button data-skip="25" class="player__button">25s >></button>
</div>
</div>
逻辑
js
/* Get Our Elements */
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('[data-skip]');
const ranges = player.querySelectorAll('.player__slider');
/* Build out functions */
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() {
video[this.name] = this.value;
}
function handleProgress() {
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);
video.addEventListener('play', updateButton);
video.addEventListener('pause', updateButton);
video.addEventListener('timeupdate', handleProgress);
toggle.addEventListener('click', togglePlay);
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);
建议直接去看Soyaine的中文详解