简介:当使用到 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>
复制