播放器
目的:可快退、快进、静音、调节声音、全屏、改变当前视频所在位置(以拖动形式和点击进度条的形式)
遇到的问题:
① 谷歌浏览器上若用本地视频无法对video
标签进行currentTime
的设置
② 在video的oncanplay
事件触发前无法获取该视频的duration
值
③ 只要视频的时间改变都会触发ontimeupdate
事件,若想要1s进度条移动 & 1s时间变化一次,可采用对video.currentTime
向下求整的方式来实现。
④ 当video
的playbackRate
改变时,其currentTime
的改变速度变快,此时不是1s移动一次进度条 & 1s时间变化一次。而是与速度有关了,但时间仍是以整数变化的(无论是加速还是未加速,计算的currentTime
都是整数值,时间和计算的currentTime
有关,故仍以整数形式变化)。(不加快速度时,其默认播放速度为1,故可做到③)。
⑤ 在快退时,不可将video.playbackRate
设为-1。应该在定时器中减少video.currentTime
的值来实现。
1. 播放和暂停切换
在按播放时,视频开始播放,调用
video.play()
方法。在按暂停时,视频停止播放,调用video.pause()
方法。在后续的快进和快退功能下,video.playbackRate
会发生变化,当点击快进按钮时,若想要速度变为正常则需要点击暂停按钮,再点击播放按钮,此时播放速度变为正常速度。
play.onclick = function () {
clearInterval(timer);
if(this.innerHTML=="播放"){
this.innerHTML="暂停";
video.play();
}else{
this.innerHTML = "播放";
video.pause();
}
video.playbackRate = 1;
range.value = initVolume * 100;
};
2. 视频时间变化
在视频时间变化时,进度条、圆圈的位置以及当前视频时间也需要变化。由于视频时间只要变化就会调用
ontimeupdate
方法,若想1s变化一次,则可通过对currentTime
向下求整的方式来实现。当视频播放到结尾时,currentTime
变为0,暂停变为播放,即跳到视频的开始。用户点击播放可重新开始播放
video.ontimeupdate = function(){
if(video.currentTime<=0){
clearInterval(timer)
}
var currentTime = Math.floor(this.currentTime);//将当前时间向下求整做到变化几次当前时间后才移动进度条长度
var width = (currentTime/this.duration)*parseInt(progressWidth);
progressInner.style.width = width+"px";
circle.style.left = (width-parseInt(circleWidth)/2)+"px";
nowTime.innerHTML = setTime(currentTime);
if(this.currentTime>=this.duration){
play.innerHTML="播放";
this.currentTime = 0;
}
};
3. 快进 & 快退
当点击快退时,创建计时器,视频停止播放。当快退至视频的开始时,清除计时器。
/*
* 快进
* */
go.onclick = function () {
video.playbackRate = 3;
}
/*
* 快退
* */
back.onclick = function () {
video.pause();
play.innerHTML="播放";
// video.playbackRate = -1;//不可为负数!!!
timer = setInterval(function(){
video.currentTime -= 2;
console.log(video.currentTime)
},500)
}
/*
* 全屏
* */
allScreen.onclick = function () {
/*
* 考虑兼容性
* */
if (video.requestFullscreen) {
video.requestFullscreen()
}
if (video.webkitRequestFullscreen) {
video.webkitRequestFullscreen()
}
if (video.mozRequestFullscreen) {
video.mozRequestFullscreen()
}
if (video.msRequestFullscreen) {
video.msRequestFullscreen()
}
if (video.oRequestFullscreen) {
video.oRequestFullscreen()
}
}
4. 点击进度条,跳到点击的位置
点击进度条,改变
video.currentTime
、进度条位置、圆圈位置和当前所在时间。
progress.onclick = function (e) {
var offset = e.clientX-progress.offsetLeft-videoOut.offsetLeft;
var currentTime = (offset/parseInt(progressWidth))*video.duration;
video.currentTime = currentTime;
var width = (currentTime/video.duration)*parseInt(progressWidth);
progressInner.style.width = width+"px";
circle.style.left = (width-parseInt(circleWidth)/2)+"px";
nowTime.innerHTML = setTime(currentTime);
}
5. 当拖动圆圈时,改变视频播放位置
当点击圆圈进行拖动时才能进行视频位置的移动。此时触发圆圈的
onousedown
事件。在移动的过程中,不仅可以在进度条上移动,也可以在整个视频的范围内移动,故需要设置视频的onmousemove
事件,在其onmouseup
事件触发的同时清除其onmousemove
事件
circle.onmousedown = function() {
videoOut.onmousemove = function (e) {
var offset = e.clientX - this.offsetLeft - progress.offsetLeft;
if (offset <= 300 && offset >= 0) {
video.currentTime = (offset / parseInt(progressWidth)) * video.duration;
progressInner.style.width = offset + "px";
circle.style.left = (offset - parseInt(circleWidth) / 2) + "px";
}
}
};
videoOut.onmouseup = function(){
//若外层写成video.onmouseup事件,则在底部progress处无法触发。。因为progress将其挡住
this.onmousemove = null;//清空事件内容
};
完整代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<style>
.video{
width: 600px;
height: 400px;
position: absolute;
left: 0;
right: 0;
margin:auto;
border:1px solid black;
background: black;
}
.video>video{
width: 600px;
height: 400px;
}
.video>.controls{
width: 100%;
position: absolute;
bottom: 0;
height: 40px;
background: white;
}
.controls>div:not(.time){
border-radius:50%;
color: white;
width: 30px;
height: 30px;
text-align: center;
line-height: 30px;
background: black;
font-size: 12px;
position: absolute;
top:0;
bottom:0;
margin:auto;
}
.go{
left:32px;
}
.back{
left:64px
}
.progress{
border-radius:5px !important;
left:96px;
width: 300px !important;
height: 6px !important;
background: silver !important;
}
.progressInner{
background:gray;
height:100%;
width: 0;
}
.progress>.circle{
position:absolute;
top:-3px;
left:-6px;
display: inline-block;
border-radius:50%;
background: black;
width: 12px;
height: 12px;
}
.mute{
right: 64px;
}
.volume{
right: 32px;
}
.allScreen{
right: 2px;
}
.time{
position: absolute;
right: 98px;
line-height: 40px;
font-size: 12px;
}
#range{
display: none;
transform:rotate(-90deg) !important;
position: absolute;
right: -18px;
bottom: 90px;
}
</style>
<body>
<div class="video">
<video src="http://smvideo.duowan.com/video_upload/14031.mp4"></video><!--谷歌浏览器上若用本地视频无法对其进行currentTime的设置-->
<div class="controls">
<div class="play">播放</div>
<div class="go">快进</div>
<div class="back">快退</div>
<div class="progress">
<div class="progressInner">
</div>
<span class="circle"></span>
</div>
<div class="time">
<span class="nowTime">00:00:00</span>/
<span class="allTime">00:00:45</span>
</div>
<div class="mute" data-num="0">静音</div>
<div class="volume">音量</div>
<div class="allScreen">全屏</div>
<input type="range" value="0" min="0" max="100" id="range" orient="vertical">
</div>
</div>
<script>
var play = document.getElementsByClassName("play")[0];
var range = document.getElementById("range");
var go = document.getElementsByClassName("go")[0];
var back = document.getElementsByClassName("back")[0];
var video = document.getElementsByTagName("video")[0];
var nowTime = document.getElementsByClassName("nowTime")[0];
var videoOut = document.getElementsByClassName("video")[0];
var allTime = document.getElementsByClassName("allTime")[0];
var allScreen = document.getElementsByClassName("allScreen")[0];
var progress = document.getElementsByClassName("progress")[0];
var progressInner = document.getElementsByClassName("progressInner")[0];
var circle = document.getElementsByClassName("circle")[0];
var mute = document.getElementsByClassName("mute")[0];
var volume = document.getElementsByClassName("volume")[0];
var timer;
var speed=1000;
var oldSpeed;
var initVolume;
var nowVolume;
var progressWidth = window.getComputedStyle(progress).width;
var circleWidth = window.getComputedStyle(circle).width;
circle.onmousedown = function() {
videoOut.onmousemove = function (e) {
var offset = e.clientX - this.offsetLeft - progress.offsetLeft;
if (offset <= 300 && offset >= 0) {
video.currentTime = (offset / parseInt(progressWidth)) * video.duration;
progressInner.style.width = offset + "px";
circle.style.left = (offset - parseInt(circleWidth) / 2) + "px";
}
}
};
// progress.onmousemove = function (e) {//只在进度条控制
// var offset = e.clientX-this.offsetLeft-videoOut.offsetLeft;
// if(offset<=300 && offset>=0){
// video.currentTime = (offset/parseInt(progressWidth))*video.duration;
// progressInner.style.width = offset+"px";
// circle.style.left = (offset-parseInt(circleWidth)/2)+"px";
// }
// }
videoOut.onmouseup = function(){
//若外层写成video.onmouseup事件,则在底部progress处无法触发。。因为progress将其挡住
this.onmousemove = null;//清空事件内容
};
volume.onclick = function(){
if(range.style.display == "block"){
range.style.display = "none";
}else{
range.style.display = "block";
}
};
range.onchange = function(){
var rate = this.value/this.max;
video.volume = initVolume*rate;
nowVolume = initVolume*rate;
};
mute.onclick = function(){
if(this.getAttribute("data-num")=="0"){
video.muted = true;
this.setAttribute("data-num","1");
range.value = 0;
mute.style.background="red"
}else{
video.muted = false;
this.setAttribute("data-num","0");
range.value = nowVolume*range.max;
mute.style.background=""
}
};
video.oncanplay = function () {
allTime.innerHTML = setTime(this.duration);
oldSpeed = this.playbackRate;
initVolume = this.volume;
nowVolume = initVolume;
};
/*
* 设置总时间和当前时间
* */
function setTime(time){
var str = "";
var time = time;
var hour = Math.floor((time/(60*60))%(24));
str += hour<10 ? "0"+hour : hour;
var minute = Math.floor((time/60)%60);
str += minute<10 ? ":0"+minute : ":"+minute;
var second = Math.floor(time%60);
str += second<10 ? ":0"+second : ":"+second;
return str;
}
/*
* 切换播放和暂停
* */
play.onclick = function () {
clearInterval(timer);
if(this.innerHTML=="播放"){
this.innerHTML="暂停";
video.play();
}else{
this.innerHTML = "播放";
video.pause();
}
video.playbackRate = 1;
range.value = initVolume * 100;
};
/*
* 时间变化时调用
* */
video.ontimeupdate = function(){
if(video.currentTime<=0){
clearInterval(timer)
}
var currentTime = Math.floor(this.currentTime);//将当前时间向下求整做到变化几次当前时间后才移动进度条长度
var width = (currentTime/this.duration)*parseInt(progressWidth);
progressInner.style.width = width+"px";
circle.style.left = (width-parseInt(circleWidth)/2)+"px";
nowTime.innerHTML = setTime(currentTime);
if(this.currentTime>=this.duration){
play.innerHTML="播放";
this.currentTime = 0;
}
};
/*
* 快进
* */
go.onclick = function () {
video.playbackRate = 3;
}
/*
* 快退
* */
back.onclick = function () {
video.pause();
play.innerHTML="播放";
// video.playbackRate = -1;//不可为负数!!!
timer = setInterval(function(){
video.currentTime -= 2;
console.log(video.currentTime)
},500)
}
/*
* 全屏
* */
allScreen.onclick = function () {
/*
* 考虑兼容性
* */
if (video.requestFullscreen) {
video.requestFullscreen()
}
if (video.webkitRequestFullscreen) {
video.webkitRequestFullscreen()
}
if (video.mozRequestFullscreen) {
video.mozRequestFullscreen()
}
if (video.msRequestFullscreen) {
video.msRequestFullscreen()
}
if (video.oRequestFullscreen) {
video.oRequestFullscreen()
}
}
/*
* 点击进度条
* */
progress.onclick = function (e) {
var offset = e.clientX-progress.offsetLeft-videoOut.offsetLeft;
var currentTime = (offset/parseInt(progressWidth))*video.duration;
video.currentTime = currentTime;
var width = (currentTime/video.duration)*parseInt(progressWidth);
progressInner.style.width = width+"px";
circle.style.left = (width-parseInt(circleWidth)/2)+"px";
nowTime.innerHTML = setTime(currentTime);
}
</script>
</body>
</html>