<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="./test.css">
<!-- -->
</head>
<body>
<div class="common-player_video_container_wrapper" id="videoplayer">
<div class="common-player_video_container">
<video class="" id="video" src="./1.mp4">
</video>
</div>
<div class="common-player_video_control">
<div class="_video_control_top">
<div class="_video_control_left">
<div class="_video_control_start_wrapper">
<span class="_video_control_btn _video_control_play"></span>
</div>
<div class="_video_control_time_wrapper">
<span class="_video_control_font current_time">00:00:00</span>
<span class="_video_control_font">/</span>
<span class="_video_control_font total_time"></span>
</div>
</div>
<div class="_video_control_right">
<div class="_video_control_voice_compnent">
<div class="_video_control_voice_progress_wrapper bar">
<div class="_video_control_voice_progress progress"></div>
<div class="_video_control_voice_progress_btn dot"></div>
</div>
<div class="_video_control_voice_wrapper">
<span class="_video_control_btn _video_control_soundon"></span>
</div>
</div>
<div class="_video_control_fullscreen_wrapper">
<span class="_video_control_btn _video_control_fullscreen"></span>
</div>
<div class="_video_control_speed_wrapper">
<div class="_video_control_speed_panel _video_control_font">
<ul>
<li>0.5</li>
<li class="_active">1.0</li>
<li>1.5</li>
<li>2.0</li>
</ul>
</div>
<span class="_video_control_speed _video_control_font">1.0</span>
</div>
</div>
</div>
<div class="_video_control_bottom ">
<div class="_video_control_progress_wrapper bar">
<div class="_video_control_progress progress"></div>
<div class="_video_control_progress_btn dot"></div>
</div>
</div>
</div>
</div>
<script src="./test.js"></script>
</body>
</html>
/* 基础布局*/
.common-player_video_container_wrapper {
position: relative;
width: 500px;
/* height: 500px; */
background-color: #000;
margin: auto;
}
.common-player_video_container_wrapper video {
width: 100%;
}
ul {
list-style: none;
margin: 0;
padding: 0;
}
ul li {
text-align: center;
padding: 6px 0;
}
ul li:hover {
background-color: #888888;
}
/* .common-player_video_flv:hover .common-player_video_control {
display: block;
} */
.common-player_video_container {
width: 100%;
height: 100%;
display: flex;
align-items: center;
}
.common-player_video_control {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 60px;
padding-top: 10px;
/* background-color: rgba(255, 255, 255, 0.8); */
background: -moz-linear-gradient(top, rgba(0, 0, 0, 0), rgba(0, 0, 0, 1));
/* Firefox */
background: -webkit-linear-gradient(top, rgba(0, 0, 0, 0), rgba(0, 0, 0, 1));
/* Safari 和 Chrome */
background: -o-linear-gradient(top, rgba(0, 0, 0, 0), rgba(0, 0, 0, 1));
/* Opera */
background: linear-gradient(to bottom, rgba(0, 0, 0, 0), rgba(0, 0, 0, 1));
/* 标准的语法 */
}
._video_control_top {
width: 100%;
height: 30px;
/* background-color: #f66; */
display: flex;
justify-content: space-between;
align-items: center;
}
._video_control_bottom {
width: 100%;
height: 18px;
padding: 0 10px;
box-sizing: border-box;
display: flex;
align-items: center;
}
._video_control_left {
display: flex;
align-items: center;
}
._video_control_right {
display: flex;
align-items: center;
}
._video_control_font {
font-size: 12px;
user-select: none;
color: #fff;
}
/* 播放进度控制*/
._video_control_progress_wrapper {
width: 100%;
background-color: #ccc;
height: 4px;
position: relative;
border-radius: 4px;
cursor: pointer;
}
._video_control_progress {
width: 10px;
background-color: #fff;
height: 4px;
position: absolute;
top: 0;
left: 0;
border-radius: 4px;
}
._video_control_progress_btn {
width: 12px;
height: 12px;
border-radius: 6px;
background-color: #fff;
position: absolute;
top: -4px;
left: 0px;
cursor: pointer;
}
/* 倍速控制*/
._video_control_speed_wrapper {
position: relative;
}
._video_control_speed_wrapper:hover ._video_control_speed_panel {
display: block;
}
._video_control_speed_panel {
position: absolute;
width: 40px;
bottom: 30px;
left: -4px;
background-color: rgba(0, 0, 0, 0.7);
border-radius: 8px;
overflow: hidden;
display: none;
}
._video_control_speed {
cursor: pointer;
}
._active {
background-color: #ccc;
}
/* 音量控制*/
._video_control_voice_compnent {
position: relative;
display: flex;
align-items: center;
border-radius: 40px;
padding-left: 20px;
}
._video_control_voice_compnent:hover {
transition: all 0.5s;
background-color: rgba(0, 0, 0, 0.6);
}
._video_control_voice_compnent:hover ._video_control_voice_progress_wrapper {
visibility: visible;
}
._video_control_voice_progress_wrapper {
height: 4px;
width: 40px;
background: #ccc;
border-radius: 4px;
position: relative;
visibility: hidden;
cursor: pointer;
}
._video_control_voice_progress {
height: 4px;
width: 10px;
background: #fff;
border-radius: 4px;
position: absolute;
top: 0;
left: 0;
}
._video_control_voice_progress_btn {
width: 12px;
height: 12px;
border-radius: 6px;
background-color: #fff;
position: absolute;
top: -4px;
left: 4px;
cursor: pointer;
}
/* 基础按键*/
._video_control_start_wrapper,
._video_control_voice_wrapper,
._video_control_fullscreen_wrapper,
._video_control_speed_wrapper {
cursor: pointer;
width: 34px;
height: 34px;
margin: 0px 8px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 500px;
}
._video_control_start_wrapper:hover,
._video_control_fullscreen_wrapper:hover {
background: rgba(0, 0, 0, 0.6);
}
._video_control_btn {
display: block;
width: 14px;
height: 14px;
background-repeat: no-repeat;
background-size: cover;
}
._video_control_play {
background-image: url('./play.svg');
}
._video_control_pause {
background-image: url('./pause.svg');
}
._video_control_soundon {
background-image: url('./sound-on.svg');
}
._video_control_soundoff {
background-image: url('./sound-off.svg');
}
._video_control_fullscreen {
background-image: url('./fullscreen-enter.svg');
}
._video_control_origin {
background-image: url('./fullscreen-exit.svg');
}
function toggleBtnClass(dom, replaceArr) {
const fliterDom = dom.querySelector("._video_control_btn");
const cls = fliterDom.classList.toString();
const res = cls.includes(replaceArr[0])
? cls.replace(replaceArr[0], replaceArr[1])
: cls.replace(replaceArr[1], replaceArr[0]);
fliterDom.setAttribute("class", res);
return res;
}
function fullScreen(docElm) {
if (window.isFullScreen) {
return;
}
// const docElm = document.documentElement
if (docElm.requestFullscreen) {
docElm.requestFullscreen();
} else if (docElm.mozRequestFullScreen) {
docElm.mozRequestFullScreen();
} else if (docElm.webkitRequestFullScreen) {
docElm.webkitRequestFullScreen();
} else if (docElm.msRequestFullscreen) {
docElm.msRequestFullscreen();
}
window.isFullScreen = true;
}
function cancelFullScreen() {
if (!window.isFullScreen) {
return;
}
if (document.exitFullscreen) {
document.exitFullscreen();
} else if (document.mozCancelFullScreen) {
document.mozCancelFullScreen();
} else if (document.webkitCancelFullScreen) {
document.webkitCancelFullScreen();
} else if (document.msCancelFullScreenn) {
document.msCancelFullScreen();
}
window.isFullScreen = false;
}
let isMoving = false;
function sliderMove(range, offsetLeft, percent, isMoving) {
if (isMoving) return;
// return
var bar = range.querySelector(".bar");
var progress = range.querySelector(".progress");
var dot = range.querySelector(".dot");
var maximum = 100; // maximum最大值默认为100
// 总长度减去原点覆盖的部分
var rest = bar.offsetWidth - dot.offsetWidth;
let left = (parseFloat(percent) * rest) / maximum;
if (left < 0) {
left = 0;
}
if (left >= rest) {
left = rest;
}
dot.style.left = left + "px";
progress.style.width =
(bar.offsetWidth * Math.ceil(percent)) / maximum + "px";
}
function slider(range, offsetLeft, cb) {
var bar = range.querySelector(".bar");
var progress = range.querySelector(".progress");
var dot = range.querySelector(".dot");
var maximum = 100; // maximum最大值默认为100
// 总长度减去原点覆盖的部分
var rest = bar.offsetWidth - dot.offsetWidth;
function handelClick(left) {
isMoving = true;
if (left < 0) {
left = 0;
}
if (left >= rest) {
left = rest;
}
dot.style.left = left + "px";
let bili = (left / rest) * maximum;
cb && cb(Math.ceil(bili));
progress.style.width = (bar.offsetWidth * Math.ceil(bili)) / maximum + "px";
}
// 判断是否移动端
if (
!navigator.userAgent.match(
/(iPhone|iPod|Android|ios|iOS|iPad|Backerry|WebOS|Symbian|Windows Phone|Phone)/i
)
) {
// 鼠标按下事件
dot.onmousedown = function (ev) {
isMoving = true;
/*
* offsetLeft 获取的是相对于父对象的左边距, 返回的是数值, 没有单位
*/
let dotL = dot.offsetLeft;
let e = ev || window.event; //兼容性
/*
* clientX 事件属性返回当事件被触发时鼠标指针向对于浏览器页面(或客户区)的水平坐标。
*/
let mouseX = e.clientX; //鼠标按下的位置
window.onmousemove = function (ev) {
let e = ev || window.event;
// 浏览器当前位置减去鼠标按下的位置
let moveL = e.clientX - mouseX; //鼠标移动的距离
// 保存newL是必要的
let newL = dotL + moveL; //left值
// 判断最大值和最小值
if (newL < 0) {
newL = 0;
}
if (newL >= rest) {
newL = rest;
}
// 改变left值
dot.style.left = newL + "px";
// 计算比例
let bili = (newL / rest) * maximum;
cb && cb(Math.ceil(bili));
progress.style.width =
(bar.offsetWidth * Math.ceil(bili)) / maximum + "px";
return false; //取消默认事件
};
window.onmouseup = function () {
window.onmousemove = false; //解绑移动事件
return false;
};
return false;
};
// 点击进度条
bar.onclick = (ev) => {
console.log(ev.clientX, range.offsetLeft, offsetLeft);
let left =
ev.clientX - offsetLeft - range.offsetLeft - dot.offsetWidth / 2;
handelClick(left);
return false;
};
} else {
// 触摸事件
dot.ontouchstart = function (ev) {
isMoving = true;
let dotL = dot.offsetLeft;
let e = ev || window.event; //兼容性
let mouseX = e.touches[0].clientX; //触摸的位置
window.ontouchmove = function (ev) {
let e = ev || window.event;
// 浏览器当前位置减去鼠标按下的位置
let moveL = e.touches[0].clientX - mouseX; //触摸移动的距离
// 保存newL是必要的
let newL = dotL + moveL; //left值
// 判断最大值和最小值
if (newL < 0) {
newL = 0;
}
if (newL >= rest) {
newL = rest;
}
// 改变left值
dot.style.left = newL + "px";
// 计算比例
let bili = (newL / rest) * maximum;
cb && cb(Math.ceil(bili));
progress.style.width =
(bar.offsetWidth * Math.ceil(bili)) / maximum + "px";
return false; //取消默认事件
};
window.ontouchend = function () {
window.ontouchmove = false; //解绑移动事件
return false;
};
return false;
};
// 点击进度条
bar.ontouchstart = function (ev) {
let left =
ev.touches[0].clientX -
offsetLeft -
range.offsetLeft -
dot.offsetWidth / 2;
handelClick(left);
return false;
};
}
}
/**
* 根据秒数计算时间
*/
function dealTime(time) {
const minute = Math.floor(time / 60);
const seconds = Math.floor(time % 60);
let sec = seconds < 10 ? `0${seconds}` : seconds;
let minu = "00";
let hour = "00";
if (minute >= 60) {
hour = Math.floor(minute / 60);
hour = hour < 10 ? `0${hour}` : hour;
minu = minute % 60;
minu = minu < 10 ? `0${minu}` : minu;
} else {
minu = minute < 10 ? `0${minute}` : minute;
}
return `${hour}:${minu}:${sec}`;
}
window.onload = () => {
const _commonPlayer = document.querySelector("#videoplayer");
const vdom = _commonPlayer.querySelector("#video");
vdom.volume = 0.25;
const playDom = _commonPlayer.querySelector("._video_control_start_wrapper");
const voiceDom = _commonPlayer.querySelector("._video_control_voice_wrapper");
const fullscreenDom = _commonPlayer.querySelector(
"._video_control_fullscreen_wrapper"
);
const totalTime = _commonPlayer.querySelector(".total_time");
const currentTime = _commonPlayer.querySelector(".current_time");
totalTime.innerHTML = dealTime(parseInt(vdom.duration));
/**
* 数值为css偏移量, 初始化进度滑块、音量滑块
*/
slider(
_commonPlayer.querySelector("._video_control_bottom"),
_commonPlayer.offsetLeft + 10,
(num) => {
const curTime = Math.floor(parseInt((num * vdom.duration) / 100));
currentTime.innerHTML = dealTime(curTime);
console.log(
curTime,
vdom.duration,
vdom.duration - curTime < 1 ? vdom.duration : curTime
);
vdom.currentTime = curTime;
if( vdom.duration - vdom.currentTime < 1){
vdom.pause();
const fliterDom = playDom.querySelector("._video_control_btn");
const cls = fliterDom.classList.toString();
const res = cls.includes('pause')
? cls.replace('pause', 'play')
: cls;
fliterDom.setAttribute("class", res);
}
}
);
slider(
_commonPlayer.querySelector("._video_control_voice_compnent"),
_commonPlayer.offsetLeft + 20,
(num) => {
vdom.volume = num / 100;
const fliterDom = _commonPlayer.querySelector(
"._video_control_voice_wrapper ._video_control_btn"
);
const cls = fliterDom.classList.toString();
let res;
if (vdom.volume === 0) {
res = cls.replace("soundon", "soundoff");
} else {
res = cls.replace("soundoff", "soundon");
}
fliterDom.setAttribute("class", res);
}
);
/**
* 视频监听,时间获取
*/
let timer = null;
vdom.addEventListener("playing", () => {
const duration = vdom.duration;
timer = setInterval(() => {
const time = parseInt(vdom.currentTime) + 1;
currentTime.innerHTML = dealTime(time < duration ? time : duration);
const percent = parseFloat((vdom.currentTime * 100) / duration).toFixed(
2
);
sliderMove(
_commonPlayer.querySelector("._video_control_bottom"),
_commonPlayer.offsetLeft + 10,
percent
);
}, 1000);
});
vdom.addEventListener("pause", () => {
console.log("pause");
clearInterval(timer);
timer = null;
});
vdom.addEventListener(
"ended",
() => {
console.log("ended");
clearInterval(timer);
timer = null;
const fliterDom = playDom.querySelector("._video_control_btn");
const cls = fliterDom.classList.toString();
const res = cls.includes('pause')
? cls.replace('pause', 'play')
: cls;
fliterDom.setAttribute("class", res);
},
false
);
/**
* 倍速逻辑
*/
const ptn = _commonPlayer.querySelector("._video_control_speed_panel");
ptn.onclick = (e) => {
const len = e.target.parentElement.children.length;
for (let i = 0; i < len; i++) {
e.target.parentElement.children[i].setAttribute("class", "");
}
_commonPlayer.querySelector("._video_control_speed").innerHTML =
e.target.innerHTML;
vdom.playbackRate = parseFloat(e.target.innerHTML);
e.target.setAttribute("class", "_active");
};
/**
* 播放暂停逻辑
*/
playDom.onclick = (e) => {
if( vdom.duration - vdom.currentTime < 1){
vdom.currentTime = 0;
}
const res = toggleBtnClass(playDom, ["play", "pause"]);
if (res.includes("play")) {
vdom.pause();
} else {
if(vdom.currentTime === 0){
sliderMove(
_commonPlayer.querySelector("._video_control_bottom"),
_commonPlayer.offsetLeft + 10,
0
);
}
vdom.play();
}
};
/**
* 静音播放逻辑
*/
voiceDom.onclick = () => {
const res = toggleBtnClass(voiceDom, ["soundon", "soundoff"]);
vdom.volume = res.includes("soundon") ? 0.25 : 0;
console.log(vdom.volume);
sliderMove(
_commonPlayer.querySelector("._video_control_voice_compnent"),
_commonPlayer.offsetLeft + 20,
vdom.volume * 100
);
};
/**
* 全屏取消全屏逻辑
*/
fullscreenDom.onclick = () => {
const res = toggleBtnClass(fullscreenDom, ["fullscreen", "origin"]);
if (res.includes("origin")) {
fullScreen(_commonPlayer);
} else {
cancelFullScreen();
}
};
};
最终预览效果:文章来源:https://www.toymoban.com/news/detail-770119.html
文章来源地址https://www.toymoban.com/news/detail-770119.html
到了这里,关于原生JavaScript实现video视频控制栏的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!