HTML 元素用于在HTML或者XHTML文档中嵌入媒体播放器,用于支持文档内的视频播放。
currentTime
:读取 CurentTime
返回一个双精度浮点值,指示以秒为单位的媒体的当前播放位置。如果video尚未开始播放,则会在开始播放后返回偏移量。通过 CurentTime
将当前播放位置设置为给定时间,会在加载媒体时将媒体查找到该位置(从指定的位置开始播放)。* duration
(只读):一个双精度浮点值,它指示媒体的持续时间(总长度),以秒为单位,在媒体的时间线上。* volume
:音量* playbackrate
:播放速度* play()
:播放视频* pause()
:暂停视频更多属性:developer.mozilla.org/zh-CN/docs/…实现思路:
1.播放 / 暂停
// 获取 dom 节点
const player = document.querySelector('.player')
const video = player.querySelector('.viewer')
const toggle = player.querySelector('.toggle')
当 video 标签和 控制按钮被点击时,切换播放状态
video.addEventListener('click', togglePlay)
toggle.addEventListener('click', togglePlay)
判断 video 的状态,如果当前是暂停,则调用 video 的 play。
// 切换播放状态
function togglePlay() {const method = video.paused ? 'play' : 'pause'video[method]()
}
2.切换播放状态图标,对 video 进行播放状态的监听
video.addEventListener('play', updatedToggle)
video.addEventListener('pause', updatedToggle)
// 切换播放状态图标
function updatedToggle() {const icon = video.paused ? '►' : '❚ ❚'toggle.textContent = icon
}
3.实现前进后退功能
获取页面上的两个前进后退按钮,为其添加 click
事件。
const skipButtons = player.querySelectorAll('[data-skip]')
skipButtons.forEach(skipButton => skipButton.addEventListener('click', skip))
获取 skip 按钮上的自定义属性,改变 video 的 currentTime
function skip() {video.currentTime += parseFloat(this.dataset.skip)
}
4.改变播放速度和音量
获取页面上控制音量和播放速度的两个按钮,为其添加 change
事件和 mousemove
事件,实现点击或拖动改变的效果。
const ranges = player.querySelectorAll('.player__slider')
ranges.forEach(range => range.addEventListener('change', handleRangeUpdate))
ranges.forEach(range => range.addEventListener('mousemove', handleRangeUpdate))
// 改变播放速度和音量
function handleRangeUpdate() {video[this.name] = this.value
}
5.实现播放进度条的颜色移动
const progressBar = player.querySelector('.progress__filled')
监听 video
标签的 timeupdate
video.addEventListener('timeupdate', handleProgress)
用当前播放的时间 video.currentTime
除以视频的总时长 video.duration
// 改变进度条
function handleProgress() {const percent = (video.currentTime / video.duration) * 100;progressBar.style.flexBasis = `${percent}%`;
}
6.拖动进度条,视频切换到对应的播放时间
const progress = player.querySelector('.progress')
需要一个变量,控制切换是否生效
let mousedown = false
监听 progress 的 click
,mousemove
,mousedown
,mouseup
四个事件
let mousedown = false
progress.addEventListener('click', scrub)
progress.addEventListener('mousemove', (e) => mousedown && scrub(e))
progress.addEventListener('mousedown', () => mousedown = true)
progress.addEventListener('mouseup', () => mousedown = false)
// 点击切换播放进度
function scrub(e) {const scrubTime = (e.offsetX / progress.offsetWidth) * video.durationvideo.currentTime = scrubTime
}
隐藏原生 video 控件,实现原生控件的功能。
传入的 controls 的是控件的数量,通过该数组来控制显示。
播放 / 暂停
{controls.includes('play') ? ({isPlaying ? 'Pause' : 'Play'}
) : null}
显示播放时间
对传入的时间做一些格式化操作
const getTimeCode = (secs: number): string => {let secondsNumber = secs ? parseInt(String(secs), 10) : 0;let hours = Math.floor(secondsNumber / 3600);let minutes = Math.floor((secondsNumber - hours * 3600) / 60);let seconds = secondsNumber - hours * 3600 - minutes * 60;let hoursStr: string = String(hours);let minutesStr: string = String(minutes);let secondsStr: string = String(seconds);if (hours < 10) {hoursStr = '0' + hours;}if (minutes < 10) {minutesStr = '0' + minutes;}if (seconds < 10) {secondsStr = '0' + seconds;}return `${hoursStr !== '00' ? hoursStr + ':' : ''}${minutesStr}:${secondsStr}`;
};
const durationTimeCode = getTimeCode(Math.ceil(duration));
const currentTimeCode =currentTime !== duration ? getTimeCode(currentTime) : durationTimeCode;
{controls.includes('time') ? ({currentTimeCode}/{durationTimeCode}
) : null}
进度条组件,通过 ref 向父组件暴露子组件的引用。Marker 是标记点组件,接收传入的数组,向外暴露 onMarkerClick 事件。
{controls.includes('progress') ? ({markers &&markers.map((marker, index) => {return ( );})}
) : null}
Marker 组件本质上是有 i 标签组成的一个个小点,通过传入的 duration 和 time 计算出 position 的值。
if (duration) {const percent = time <= duration ? time / duration : 1;return `calc(${percent * 100}% - 2px)`;
}
{onMarkerClick(marker);}}
/>
控制音量组件
{controls.includes('volume') ? ({volume * 100}% volumeVolume
) : null}
全屏组件
{controls.includes('full-screen') ? (
) : null}
进度条事件如下:
Controls 组件通过 isPlaying 来判断当前的播放状态。当触发 play 和 pause 事件时,应当改变 isPlaying 的值。
play 和 pause
// play
const play = () => {if (!videoRef.current) return;const playPromise = videoRef.current.play();playPromise &&playPromise.then(() => { }).catch(e => {console.log('Operation is too fast, audio play fails');});setIsPlaying(true);
};
// pause
const pause = () => {if (!videoRef.current) return;videoRef.current.pause();setIsPlaying(false);
};
handleProgressClick
点击进度条,期望就是 video 的时间可以到达点击的位置。
left
, top
, right
, bottom
, x
, y
, width
, 和 height
这几个以像素为单位的只读属性用于描述整个边框。除了width
和 height
以外的属性是相对于视图窗口的左上角来计算的。const handleProgressClick = (e: Event) => {const x =e['clientX'] -progressEl.current!.getBoundingClientRect().left +document.body.scrollLeft;const percentage =(x * progressEl.current!.max) / progressEl.current!.offsetWidth;videoRef.current!.currentTime =(percentage / 100) * videoRef.current!.duration;
}; (percentage / 100) * videoRef.current!.duration; };
handleVolumeClick
音量的改变与进度条同理。当改变的音量的时候,静音状态应该设置为 false。
const handleVolumeClick = e => {const y =volumeEl.current!.offsetWidth -(e.clientY -volumeEl.current!.getBoundingClientRect().top +document.body.scrollTop);const percentage =(y * volumeEl.current!.max) / volumeEl.current!.offsetWidth;videoRef.current!.muted = false;const volume = videoRef.current.volume;onVolumechange?.(volume);setVolume(percentage / 100);
};
handleMuteClick,设置 muted 的状态
const handleMuteClick = () => {if (muted) {videoRef.current!.muted = false;setVideoMuted(false);} else {videoRef.current!.muted = true;setVolume(0);setVideoMuted(true);}
};
handleFullScreenClick
通过 isFullScreen 来控制是否全屏。点击全屏的时候,调用当前元素上的 requestFullscreen 方法,退出全屏时,调用 document 的 exitFullscreen 方法。
const handleFullScreenClick = () => {const videoWrap = document.getElementsByClassName('react-video-wrap')[0];if (isFullScreen) {document.body.classList.remove('react-video-full-screen');if (document['exitFullscreen']) {document['exitFullscreen']();} else if (document['mozCancelFullScreen']) {document['mozCancelFullScreen']();} else if (document['webkitExitFullscreen']) {document['webkitExitFullscreen']();} else if (document['msExitFullscreen']) {document['msExitFullscreen']();}} else {document.body.classList.add('react-video-full-screen');if (videoWrap['requestFullscreen']) {videoWrap['requestFullscreen']();} else if (videoWrap['mozRequestFullScreen']) {videoWrap['mozRequestFullScreen']();} else if (videoWrap['webkitRequestFullscreen']) {videoWrap['webkitRequestFullscreen']();} else if (videoWrap['msRequestFullscreen']) {videoWrap['msRequestFullscreen']();}}setIsFullScreen(!isFullScreen);
};
handleMarkerClick
点击标记点,进度条到达标记点的时间
const handleMarkerClick = (marker: object) => {videoRef.current!.currentTime = marker['time'];onMarkerClick(marker);
};
最近找到一个VUE的文档,它将VUE的各个知识点进行了总结,整理成了《Vue 开发必须知道的36个技巧》。内容比较详实,对各个知识点的讲解也十分到位。
有需要的小伙伴,可以点击下方卡片领取,无偿分享