简介:当使用到 HTML5 媒体播放器(<video>、<audio>),往往有许多自定义的需求,其中自定义播放进度条就是其中一种常见的需求,因此,这里通过html、css 和 js 实现一简单的媒体播放器进度条,文中简单实现其主要功能,包括加载,点击,拖拽等,若有自定义需求,可在此基础上拓展。
1、绘制基本进度条
关于进度条的实现有很多种方式,也有很多种现成的组件可以使用,在实际项目开发中,可以根据需求选择。但这里还是选择自己来手动实现一简单的进度条,进度条的实现方式大同小异,自定义的进度条有很大的拓展性。
1.1、html 结构
- 基本说明在代码中体现
<div class="box">
<!-- 媒体容器 -->
<div class="media-box"></div>
<!-- 进度条容器 -->
<div id="slide-box">
<div id="slide">
<div id="slide-inside"></div>
</div>
</div>
</div>
1.2、css样式
- 样式包括后面用到的元素,现在可只关注上面代码中用到的元素样式。
<style>
*{
box-sizing: border-box;
margin: 0;
padding: 0;
}
.box{
width: 800px;
margin: 50px auto ;
}
.media-box{
width: 800px;
height: 400px;
border: 1px solid #000;
}
#slide-box{
margin-top: 20px;
width: 700px;
height: 26px;
padding: 8px 0;
cursor: pointer;
}
#slide{
height: 10px;
position: relative;
background-color: #e4e7ed;
border-radius: 8px;
}
#slide-progress, #slide-inside{
position: absolute;
top: 0;
left: 0;
height: 100%;
border-radius: 8px;
}
#slide-progress{
background-color: #c6c8c9;
width: 50%;
transition: all ease 2s;
}
#slide-inside{
background-color: #f98e2d;
z-index: 10;
width: 30%;
transition: all ease 0.5s;
}
#point-box{
width: 24px;
height: 24px;
position: absolute;
top: 50%;
left: 30%;
transform: translate(-50%,-50%);
z-index: 11;
}
.point{
position: absolute;
border: 12px solid #fff;
box-shadow: 1px 1px 2px #454343;
border-radius: 50%;
}
.point:hover{
transform: scale(1.2);
}
</style>
1.3、js代码
- 让进度条自己简单动起来
let slideInsideDom = document.getElementById('slide-inside')
let step = 0
let max = 100
let si = setInterval(() => {
step += 1
step = step >= max ? max : step
slideInsideDom.style.width = (step / max ) * 100 + '%'
if(step >= max){
clearInterval(si)
}
}, 100);
这样就实现了一个简单的可用于展示的进度条,长这样:
现在离目标动能还缺少:
- 需要有一个显示加载进度的背景
- 需要有一个用于拖拽的元素
- js添加拖拽功能
2、播放器进度条
2.1、html
在上面的基础上添加:
<div class="box">
<!-- 媒体容器 -->
<div class="media-box"></div>
<!-- 进度条容器 -->
<div id="slide-box">
<div id="slide">
<!-- 加载进度 -->
<div id="slide-progress"></div>
<!-- 主进度 -->
<div id="slide-inside"></div>
<!-- 拖拽元素 -->
<div id="point-box">
<div class="point"></div>
</div>
</div>
</div>
</div>
样式看上面 1.2,上面是全部样式。
2.2 js实现拖拽功能
主要代码实现:
<script>
let slideDom = document.getElementById('slide-box')
let slideInsideDom = document.getElementById('slide-inside')
let pointBoxDom = document.getElementById('point-box')
// 获取外层长度
let extent = slideDom.getBoundingClientRect().width
slideDom.addEventListener('mousedown',mousedownFun)
document.addEventListener('mouseup',mouseupFun)
// 监听进度条鼠标按下
function mousedownFun(e){
setPosition(e)
console.log('进度条鼠标按下',e.clientX,slideDom.offsetLeft);
document.addEventListener('mousemove',mousemoveFun)
}
function mousemoveFun(e){
e=e || window.event;
pauseEvent(e);
console.log('拖拽移动');
setPosition(e)
}
function mouseupFun(e){
console.log('鼠标抬起',e.clientX);
document.removeEventListener('mousemove',mousemoveFun)
}
function setPosition(e){
// 计算拖动长度
let x = e.clientX - slideDom.offsetLeft
x = x < 0 ? 0 : x
x = x >= extent ? extent : x
slideInsideDom.style.width = ( x / extent ) * 100 + '%'
pointBoxDom.style.left = ( x / extent ) * 100 + '%'
}
//阻止事件冒泡
//不仅仅要stopPropagation,还要preventDefault
function pauseEvent(e){
if(e.stopPropagation) e.stopPropagation();
if(e.preventDefault) e.preventDefault();
e.cancelBubble=true;
e.returnValue=false;
return false;
}
</script>
计算 slide-box 盒子长度
监听 slide-box 盒子 鼠标按下事件,setPosition 计算出鼠标当前横向位置与 slide-box 横向距离的差值,通过差值计算出 slide-inside 长度和 point-box 位置
css 文件中 transition 后面的时间需要去掉(添加时间是让 目录1 中效果更明显),
注意:mouseup 事件可能某些情况乱下监听不到,需要拖拽时禁用默认行为并且阻止冒泡;
可参考 JS中mouseup事件丢失的原因与解决办法
以上就基本实现一个进度条的基本功能了,在鼠标按下、鼠标移动拖拽的回调函数中可以实现媒体元素的操作。
下一篇介绍与媒体播放器的交互:HTML5 媒体播放器 video、audio 自定义播放器进度条(下)
完整代码
可直接在网页运行
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
*{
box-sizing: border-box;
margin: 0;
padding: 0;
}
.box{
width: 800px;
margin: 50px auto ;
}
.media-box{
width: 800px;
height: 400px;
border: 1px solid #000;
}
#slide-box{
margin-top: 20px;
width: 700px;
height: 26px;
padding: 8px 0;
cursor: pointer;
}
#slide{
height: 10px;
position: relative;
background-color: #e4e7ed;
border-radius: 8px;
}
#slide-progress, #slide-inside{
position: absolute;
top: 0;
left: 0;
height: 100%;
border-radius: 8px;
}
#slide-progress{
background-color: #c6c8c9;
width: 50%;
transition: all ease;
}
#slide-inside{
background-color: #f98e2d;
z-index: 10;
width: 30%;
transition: all ease;
}
#point-box{
width: 24px;
height: 24px;
position: absolute;
top: 50%;
left: 30%;
transform: translate(-50%,-50%);
z-index: 11;
}
.point{
position: absolute;
border: 12px solid #fff;
box-shadow: 1px 1px 2px #454343;
border-radius: 50%;
}
.point:hover{
transform: scale(1.2);
}
</style>
</head>
<body>
<div class="box">
<!-- 媒体容器 -->
<div class="media-box"></div>
<!-- 进度条容器 -->
<div id="slide-box">
<div id="slide">
<!-- 加载进度 -->
<div id="slide-progress"></div>
<!-- 主进度 -->
<div id="slide-inside"></div>
<!-- 拖拽元素 -->
<div id="point-box">
<div class="point"></div>
</div>
</div>
</div>
</div>
<script>
let slideDom = document.getElementById('slide-box')
let slideInsideDom = document.getElementById('slide-inside')
let pointBoxDom = document.getElementById('point-box')
// 获取外层长度
let extent = slideDom.getBoundingClientRect().width
slideDom.addEventListener('mousedown',mousedownFun)
document.addEventListener('mouseup',mouseupFun)
// 监听进度条鼠标按下
function mousedownFun(e){
setPosition(e)
console.log('进度条鼠标按下',e.clientX,slideDom.offsetLeft);
document.addEventListener('mousemove',mousemoveFun)
}
function mousemoveFun(e){
e=e || window.event;
pauseEvent(e);
console.log('拖拽移动');
setPosition(e)
}
function mouseupFun(e){
console.log('鼠标抬起',e.clientX);
document.removeEventListener('mousemove',mousemoveFun)
}
function setPosition(e){
// 计算拖动长度
let x = e.clientX - slideDom.offsetLeft
x = x < 0 ? 0 : x
x = x >= extent ? extent : x
slideInsideDom.style.width = ( x / extent ) * 100 + '%'
pointBoxDom.style.left = ( x / extent ) * 100 + '%'
}
//阻止事件冒泡
//不仅仅要stopPropagation,还要preventDefault
function pauseEvent(e){
if(e.stopPropagation) e.stopPropagation();
if(e.preventDefault) e.preventDefault();
e.cancelBubble=true;
e.returnValue=false;
return false;
}
// let step = 0
// let max = 100
// let si = setInterval(() => {
// step += 1
// step = step >= max ? max : step
// slideInsideDom.style.width = (step / max ) * 100 + '%'
// if(step >= max){
// clearInterval(si)
// }
// }, 100);
</script>
</body>
</html>