原生JavaScript实现video视频控制栏

这篇具有很好参考价值的文章主要介绍了原生JavaScript实现video视频控制栏。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

<!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();
        }
    };
};

最终预览效果:

htmlvideo开启原生工具栏,javascript,音视频,开发语言文章来源地址https://www.toymoban.com/news/detail-770119.html

到了这里,关于原生JavaScript实现video视频控制栏的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • html 中video实现切换视频自动播放

    vue2实现的网页中播放视频,主要代码如下: 现在遇到的问题的,视频切换后要手动点击才能播放,是否可以实现切换视频后会自动播放不用手动点击 增加 autoplay 属性就可以了。 要实现切换视频后自动播放,您需要在 video 元素上使用 autoplay 属性。该属性会告诉浏览器在视频

    2024年01月22日
    浏览(29)
  • java实现video标签视频流播放

    问题: 在遇到video标签播放后端视频源时问题。直接返回文件流的话 video需要将文件整个下载一次才会播放。这样如果小文件没有问题。如果文件大的话就比较恶心了。 解决方案:通过模拟video标签默认的range bytes规范方法分段获取视频信息。 video标签是通过请求头带上 Ran

    2024年02月14日
    浏览(34)
  • vue 项目中使用video实现视频播放效果暂停播放(多个视频)

    根据ref判断是否暂停状态返回 true false vue 控制video视频的播放暂停(多个视频) 安装video.js 在main.js中引用 页面

    2024年02月11日
    浏览(37)
  • 手把手教你用video实现视频播放功能

    哈喽。大家好啊 今天需要做一个视频播放列表,让我想到了video的属性 下面让我们先看看实现效果 这里是我的代码 width是当前播放页面的宽度 height是当前播放页面的高度 Controls属性用就是控制栏那些了 比如播放按钮 暂停按钮 autoplay是指的是自动播放 poster是指的是初始化进

    2024年02月12日
    浏览(40)
  • springboot + vue3实现视频播放Demo(video.js & Vue3-video-play视频播放器)

    ffmpeg官网 长时长视频java存储及vue播放解决方法 【 攻城略地 】vue3 + video.js播放m3u8视频流格式 Vue3-video-play组件官网 Vue3视频播放器组件Vue3-video-play入门教程 vue-video-player播放m3u8格式的视频 Spring boot视频播放(解决MP4大文件无法播放),整合ffmpeg,用m3u8切片播放。 Java获取MP4视频文

    2024年02月07日
    浏览(39)
  • 在vue项目中使用video.js实现视频播放和视频进度条打点

    引入videojs插件 注意: controls 如果不是true的话,不会显示播放按钮 播放按钮默认在 左上角 ,是作者认为会遮挡内容考虑的,不过这个是可以根据参数修改的,只需要给video标签加一个class( vjs-big-play-centered )就可以了。 要实现的功能是视频的进度条上面有一些小点,然后

    2023年04月08日
    浏览(71)
  • Java后端接口返回视频流,使用video组件播放视频,实现分段下载

    视频文件保存在不为人知的地方,总之前端不能直接访问的位置,需要通过后端接口取出来再返回给前端。 前端这样子播放 src=后端接口 如果后端直接这样子写 小视频问题不大,视频大的话会卡顿很久,查看请求发现会先请求下载完整视频后开始播放。而且不能拖动进度条

    2024年02月12日
    浏览(32)
  • vue3-video-play 实现视频播放

    1.下载依赖 我的vue3-video-play版本是1.3.1-beta.6 2.使用html 3.在需要的页面引入。 4.附上事件列表 更详细请查看:链接: https://github.com/xdlumia/vue3-video-play/

    2024年02月11日
    浏览(32)
  • 实现html页面插入视频的自动播放、视频播放结束后的事件触发(video标签)

    要实现自动播放需要同时使用autoplay和muted属性,简单示例代码如下: html代码: css代码: 要实现视频播放结束后的事件触发需要使用addEventListener(“ended”, function () {})进行事件监听,简单示例代码如下: html代码: css代码: js代码: (1)菜鸟网址:https://www.runoob.com/tags/t

    2024年02月05日
    浏览(40)
  • uniapp - 使用 <video> 播放视频黑屏,浏览器控制台报错: DOMException: The element has on supported sources.(详细完美解决方案)

    我是uniapp全平台开发(H5 / App / 小程序),突然遇到了使用 video 标签无法播放视频的问题,直接黑屏! 并且浏览器报错:Uncaught (in promise) DOMException: The element has on supported sources.

    2024年02月16日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包