木心

毕竟几人真得鹿,不知终日梦为鱼

导航

自定义视频播放器(功能包括:播放/暂停,全屏,跳播)

最终效果:

 

1、demo结构

fontawesome字体下载:http://fontawesome.dashgame.com/

loading.gif:百度loading.gif选择一张下载

 

2、index.html

  功能包括:播放/暂停,全屏,跳播

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>自定义视频播放器</title>
    <link rel="stylesheet" href="./css/font-awesome.min.css">
    <link rel="stylesheet" href="./css/index.css">                   
</head>
<body>
<h3 class="player-title">视频播放器</h3>
<div class="player-container">
    <video src="./mp4/test.mp4"></video>
    <div class="controls-container">
        <!-- 播放/暂停 -->
        <a href="javascript:;" class="switch fa fa-play"></a>
        <!-- 全屏 -->
        <a href="javascript:;" class="expand fa fa-expand"></a>
        <!-- 进度条 -->
        <div class="progress"><!-- 进度条底色 -->
            <div class="bar"></div><!-- 进度条最外层,用于事件控制 -->
            <div class="loaded"></div><!-- 已加载 -->
            <div class="current-progress"></div><!-- 已播放 -->
        </div>
        <!-- 当前播放时间, 视频总长 -->
        <div class="time">
            <span class="current-time">00:00:00</span>
            \
            <span class="total-time">00:00:00</span>
        </div>
    </div>
</div>

<script type="text/javascript">
    // 播放器
    const video = document.querySelector('video');
    // "播放/暂停"切换按钮
    const switchBtn = document.querySelector('.switch');
    // 当前播放时间span
    const currentTimeSpan = document.querySelector('.current-time')
    // 视频总时长
    const totalTimeSpan = document.querySelector('.total-time')
    // 当前播放进度条
    const currentProgress = document.querySelector('.current-progress')
    // 获取进度条最外层,用于事件控制
    const bar = document.querySelector('.bar');

    // 实现"播放/暂停"
    switchBtn.onclick = function() {
        // 播放与暂停的切换
        if (video.paused) {
            video.play();
        } else {
            video.pause();
        }
        // 播放与暂停图标的切换
        this.classList.toggle('fa-pause');
        this.classList.toggle('fa-play');
    }

    // 实现"全屏"
    const playerContainer = document.querySelector('.player-container');
    document.querySelector('.expand').onclick = function() {
        if(playerContainer.requestFullScreen){
            playerContainer.requestFullScreen();
        } else if(playerContainer.webkitRequestFullScreen){
            playerContainer.webkitRequestFullScreen();
        } else if(playerContainer.mozRequestFullScreen){
            playerContainer.mozRequestFullScreen();
        } else if(playerContainer.msRequestFullScreen){
            playerContainer.msRequestFullScreen();
        }
    }

    // 当视频文件可以播放时触发
    // 当跳播时,修改了video.currentTime,也会触发该事件
    video.oncanplay = function() {
        console.log('触发oncanplay事件, video.currentTime=', video.currentTime)
        if (video.currentTime === 0) {
            setTimeout(function() {
                console.log('视频缓存完成,可以播放了。。。')
                // 显示视频第一帧画面
                video.style.display = 'block'
                // 获取当前视频文件总时长
                const totalTime = video.duration;
                console.log(`当前视频文件总时长: ${totalTime}秒`); // 单位为秒, 292.975736
                // 页面显示视频总时长
                totalTimeSpan.innerHTML = getTime(totalTime);
            }, 2000)
        }

    }

    // 当视频播放的时候会触发ontimeupdate事件,进度条同步,当前时间同步
    // 当跳播时,修改了video.currentTime,也会触发该事件
    video.ontimeupdate = function() {
        console.log('触发ontimeupdate事件。。。')
        // 获取当前时间
        const currentTime = video.currentTime;
        // 计算出视频的总时长
        const totalTime = video.duration;
        // 显示当前播放时间
        currentTimeSpan.innerHTML = getTime(currentTime);
        //进度条同步: 当前时间/总时间
        const value = currentTime / totalTime;
        currentProgress.style.width = value * 100 + "%";
        //当播放完毕之后,播放暂停按钮要转换成暂停按钮
        if (currentTime === totalTime) {
            switchBtn.classList.remove('fa-pause');
            switchBtn.classList.add('fa-pause');
        }
    }

    // 实现视频跳播
    bar.onclick = function(e) {
        // 获取鼠标点击位置相对bar最左侧的距离
        const offset = getOffsetX(e);
        // 获取bar的宽度
        const barWidth = this.style.width || this.clientWidth || this.offsetWidth || this.scrollWidth;
        console.log(`offset=${offset}, barWidth=${barWidth}`)
        const percent = offset / barWidth;
        const currentTime = percent * video.duration;
        video.currentTime = currentTime;
    }

    function getTime(time) {
        //转换时长
        let h = Math.floor(time / 3600);
        let m = Math.floor(time % 3600 / 60);
        let s = Math.floor(time % 60);
        //转换格式
        h = h > 10 ? h : "0" + h;
        m = m > 10 ? m : "0" + m;
        s = s > 10 ? s : "0" + s;
        return h + ":" + m + ":" + s;
    }

    // 火狐浏览器不支持e.offsetX,解决方法
    function getOffsetX(e){
        var e = e || window.event;
        var srcObj = e.target || e.srcElement;
        if (e.offsetX) {
            return e.offsetX;
        } else {
            var rect = srcObj.getBoundingClientRect();
            var clientx = e.clientX;
            return clientx - rect.left;
        }
    }
</script>
</body>
</html>

 

3、index.css

body {
    padding: 0;
    margin: 0;
    font-family: 'microsofy yahei';
    background-color: #F7F7F7;
}

a {
    text-decoration: none;
}

.player-title {
    width: 100%;
    margin: 0 auto;
    line-height: 100px;
    font-size: 40px;
    text-align: center;
}

.player-container {
    width: 720px;
    height: 360px;
    margin: 0 auto;
    background: url('../images/loading.gif') center no-repeat;
    background-size: cover;
    position: relative;
}
video {
    height: 100%;
    margin: 0 auto;
    display: none;
}

/* ================ 播放器控制面板样式 start ================ */
.controls-container {
    width: 720px;
    height: 40px;
    position: absolute;
    left: 0px;
    bottom: -40px;
    background-color: #000;
}

/* 播放/暂停 */
.controls-container .switch {
    width: 20px;
    height: 20px;
    display: block;
    font-size: 20px;
    color: #fff;
    position: absolute;
    left: 10px;
    top: 10px;
}
/* 全屏 */
.controls-container .expand {
    width: 20px;
    height: 20px;
    display: block;
    font-size: 20px;
    color: #fff;
    position: absolute;
    right: 10px;
    top: 10px;
}
/* 进度条 */
.controls-container .progress {
    width: 430px;
    height: 10px;
    position: absolute;
    left: 40px;
    bottom: 15px;
    background-color: #555;
}
.controls-container .progress .bar {
    /*width: 100%;*/
    width: 430px;
    height: 100%;
    border-radius: 3px;
    cursor: pointer;
    position: absolute;
    left: 0;
    top: 0;
    opacity: 0;
    z-index: 999;
}
.controls-container .progress .loaded {
    width: 60%; /* 视频缓存的进度, 后期可动态变化 */
    height: 100%;
    background-color: #999;
    border-radius: 3px;
    position: absolute;
    left: 0;
    top: 0;
    z-index: 2;
}
.controls-container .progress .current-progress {
    width: 0%; /* 初始播放进度为0 */
    height: 100%;
    background-color: #fff;
    border-radius: 3px;
    position: absolute;
    left: 0;
    top: 0;
    z-index: 3;
}
.controls-container .time {
    height: 20px;
    position: absolute;
    left: 490px;
    top: 10px;
    color: #fff;
    font-size: 14px;
}
/* ================ 播放器控制面板样式 end ================ */

 

4、测试

  1)打开index.html页面,视频加载完成打印"视频缓存完成,可以播放了。。。";

  2)点击进度条某个位置,首先触发了bar.onclick事件,计算并更新video.currentTime;然后触发了ontimeupdate事件和oncanplay事件。

 

  3)点击播放按钮;

  4)播放完毕后,发现一个小bug

  解决:

  删除代码:

//当播放完毕之后,播放暂停按钮要转换成暂停按钮
// if (currentTime === totalTime) {
//     switchBtn.classList.remove('fa-pause');
//     switchBtn.classList.add('fa-pause');
// }

  添加代码:

// 视频播放完毕,重置播放状态为初始状态
video.onended = function() {
    video.currentTime = 0;
    switchBtn.classList.remove('fa-pause');
    switchBtn.classList.add('fa-pause');
}

 ---

posted on 2020-02-23 13:26  wenbin_ouyang  阅读(1873)  评论(0编辑  收藏  举报