HTML5 媒体播放器 video、audio 自定义播放器进度条(下)

接上一篇:HTML5 媒体播放器 video、audio 自定义播放器进度条(上)

本篇主要介绍进度条与播放器标签的交互,以 <video> 举例,<audio>基本一样

1、结构

代码添加如下结构:

    <div class="box">
        <div class="media-box">
            <video 
              id="videoId" 
              class="video" 
              width="100%" 
              height="100%" 
              controls></video>
        </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>
        <button id="btn">开始</button>
    </div>

2、相关事件

  • 通过监听<video>相关事件,动态更新进度条

2.1、定义变量并监听事件

监听播放器主要事件之前,先定义一下变量:

        let duration = '' // 用于显示的总时长,格式 xx:xx
        let currentTime = '' // 用于显示的当前播放的时刻
        let max = '' // 总时长
        let value = '' // 当前时刻
        let video = null 
        let videoDom = document.getElementById('videoId')
        let src = ''

        videoDom.addEventListener('canplay', canplay)
        videoDom.addEventListener('timeupdate', timeupdate)
        videoDom.addEventListener('pause', videoPause)
        videoDom.addEventListener('ended', videoEnded)
        videoDom.addEventListener('error', videoError)
        videoDom.addEventListener('progress', videoProgress)

关于 <vidoe> 简介,可参考:HTML5 <video>常用属性、时间、方法及基础使用说明

2.2 canplay--媒体可播放

        function canplay(e) {
            let v = e.target;
            duration = formatterTime(v.duration);
            max = parseInt(v.duration * 1000); //目的是让进度条计算时精确,也可以不*1000
            video = v;
            console.log('canplay',max);
        }

该事件主要通过 duration 获取到总时长, 

formatterTime 函数用于格式化展示的数据:

        function formatterTime(time) {
            let minute = parseInt(time / 60);
            let seconds = parseInt(time - minute * 60);
            minute = minute < 10 ? "0" + minute : minute;
            seconds = seconds < 10 ? "0" + seconds : seconds;
            return `${minute}:${seconds}`;
        }

2.3 timeupdate--播放时间更新

        function timeupdate(e) {
            currentTime = formatterTime(e.target.currentTime);
            value = parseInt(e.target.currentTime * 1000);
            
   console.log('timeupdate',e.target.currentTime,max,`${currentTime}:${duration}`);
            // 更新进度条
            slideProcess(value)
        }

该事件主要检测视频播放时间更新,动态更新进度条

其中 slideProcess 计算:

        function slideProcess(v) {
            v = v >= max ? max : v
            slideInsideDom.style.width = (v / max) * 100 + '%'
            pointBoxDom.style.left = (v / max) * 100 + '%'
        }

2.4 progress -- 更新 加载进度

        function videoProgress(e) {
            if( e.target.buffered.length  > 0 ){
                // console.log('videoProgress-加载进度', e.target.buffered.end(0) );
                let v = e.target.buffered.end(0) * 1000
                progressDom.style.width = ( v / max) * 100 + '%'
            }
            
        }

 该事件主要用于更新加载进度

2.5 播放

定义一按钮,实现简单点击播放,到这里,进度条就可以根据视频动态更新位置及显示加载条

        let btnDom = document.getElementById('btn')
        btnDom.addEventListener('click', btnClick)


        function btnClick(e){
            pauseEvent(e)
            console.log('鼠标点击');
            init('./mov_bbb.mp4')
        }

        function init(s) {
            src = s
            if(!video)video = videoDom
            video.src = src;
            video.play()
                .then(() => {
                })
                .catch(err => {
                    console.error(err);
                    videoPause();
                });
        }

3、进度条操作

进度条的操作主要是监听鼠标按下 mousemove 和移动拖拽事件 mousemove,当按下或拖拽时,进行的操作:

  • 更新进度条样式
  • 更新 video 的 currentTime

setPosition 函数添加:

​
        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 + '%'
            // 新增如下代码
            if(video && max){
                video.currentTime = x / extent * max / 1000
            }
        }

​

一个简单的自定义进度条就实现了。 

 4、完整代码

可以将下面完整代码复制到本地运行。

<!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: 0%;
            transition: all ease;
        }

        #slide-inside {
            background-color: #f98e2d;
            z-index: 10;
            width: 0%;
            transition: all ease;
        }

        #point-box {
            width: 24px;
            height: 24px;
            position: absolute;
            top: 50%;
            left: 0%;
            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">
            <video 
              id="videoId" 
              class="video" 
              width="100%" 
              height="100%" 
              controls></video>
        </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>
        <button id="btn">开始</button>
    </div>

    <script>
        let duration = '' // 用于显示的总时长,格式 xx:xx
        let currentTime = '' // 用于显示的当前播放的时刻
        let max = '' // 总时长
        let value = '' // 当前时刻
        let video = null 
        let videoDom = document.getElementById('videoId')
        let src = ''


        let slideDom = document.getElementById('slide-box')
        let slideInsideDom = document.getElementById('slide-inside')
        let pointBoxDom = document.getElementById('point-box')
        let progressDom = document.getElementById('slide-progress')
        let extent = slideDom.getBoundingClientRect().width
        console.log(111111, extent);
        slideDom.addEventListener('mousedown', mousedownFun)
        document.addEventListener('mouseup', mouseupFun)


        videoDom.addEventListener('canplay', canplay)
        videoDom.addEventListener('timeupdate', timeupdate)
        videoDom.addEventListener('pause', videoPause)
        videoDom.addEventListener('ended', videoEnded)
        videoDom.addEventListener('error', videoError)
        videoDom.addEventListener('progress', videoProgress)

        let btnDom = document.getElementById('btn')
        btnDom.addEventListener('click', btnClick)


        function btnClick(e){
            pauseEvent(e)
            console.log('鼠标点击');
            init('./mov_bbb.mp4')
        }

        function init(s) {
            src = s
            if(!video)video = videoDom
            video.src = src;
            video.play()
                .then(() => {
                })
                .catch(err => {
                    console.error(err);
                    videoPause();
                });
        }


        function canplay(e) {
            let v = e.target;
            duration = formatterTime(v.duration);
            max = parseInt(v.duration * 1000);
            video = v;
            console.log('canplay',max);
        }

        function timeupdate(e) {
            currentTime = formatterTime(e.target.currentTime);
            value = parseInt(e.target.currentTime * 1000);
            console.log('timeupdate',e.target.currentTime,max,`${currentTime}:${duration}`);
            // 更新进度条
            slideProcess(value)
        }
        function videoPause() {
            if (video) {
                video.pause();
            }
        }
        function videoEnded() {
        }

        function videoError() {
            if (src) {
                videoPause();
            }
        }

        function videoProgress(e) {
            if( e.target.buffered.length  > 0 ){
                // console.log('videoProgress-加载进度', e.target.buffered.end(0) );
                let v = e.target.buffered.end(0) * 1000
                progressDom.style.width = ( v / max) * 100 + '%'
            }
            
        }

        function slideProcess(v) {
            // console.log('slideProcess',max);
            v = v >= max ? max : v
            slideInsideDom.style.width = (v / max) * 100 + '%'
            pointBoxDom.style.left = (v / max) * 100 + '%'
        }

        function formatterTime(time) {
            let minute = parseInt(time / 60);
            let seconds = parseInt(time - minute * 60);
            minute = minute < 10 ? "0" + minute : minute;
            seconds = seconds < 10 ? "0" + seconds : seconds;
            return `${minute}:${seconds}`;
        }

        // ----------------------- 进度条操作 -------------------------------
        // 监听进度条鼠标按下
        function mousedownFun(e) {
            setPosition(e)
            console.log('进度条鼠标按下', e.clientX, slideDom.offsetLeft);
            document.addEventListener('mousemove', mousemoveFun)
        }
        // 鼠标按下监听全局移动
        function mousemoveFun(e) {
            e = e || window.event;
            pauseEvent(e);
            setPosition(e);
            console.log('拖拽移动',);
        }
        // 全局监听鼠标抬起
        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 + '%'
            // 新增如下代码
            if(video && max){
                video.currentTime = x / extent * max / 1000
            }
        }

        //阻止事件冒泡
        //不仅仅要stopPropagation,还要preventDefault
        function pauseEvent(e) {
            if (e.stopPropagation) e.stopPropagation();
            if (e.preventDefault) e.preventDefault();
            e.cancelBubble = true;
            e.returnValue = false;
            return false;
        }

    </script>
</body>

</html>

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值