当前位置 博文首页 > 文章内容

    JS实现视频弹幕效果

    作者:shunshunshun18 栏目:未分类 时间:2021-09-10 14:43:38

    本站于2023年9月4日。收到“大连君*****咨询有限公司”通知
    说我们IIS7站长博客,有一篇博文用了他们的图片。
    要求我们给他们一张图片6000元。要不然法院告我们

    为避免不必要的麻烦,IIS7站长博客,全站内容图片下架、并积极应诉
    博文内容全部不再显示,请需要相关资讯的站长朋友到必应搜索。谢谢!

    另祝:版权碰瓷诈骗团伙,早日弃暗投明。

    相关新闻:借版权之名、行诈骗之实,周某因犯诈骗罪被判处有期徒刑十一年六个月

    叹!百花齐放的时代,渐行渐远!



    使用ES6的模块化开发及观察者模式来实现。观察者模式有很多种形式,这里是使用“注册—通知—撤销注册”的形式。TimeManager类可以返回一个单例,每一条弹幕作为一个观察者,注册到TimeManager类的单例的set表中,当单例的set中有数据时,被观察者状态被改变,执行动画,并通知所有观察者进行update状态更新。弹幕移动超过视频宽度时,从TimeManager中注销。当TimeManager单例的set表中所有被观察弹幕都注销时,setInterval停止执行。

    1、Bullet.js:

    观察者:实现弹幕样式,和自身状态更新update()方法.

    2、TimeManager.js

    被观察者和Subject:可以增加和删除观察者对象,状态改变时通知所有观察者并更新状态。

    3、Player.js

    播放器组件:简单的播放器样式,控制按钮等都是默认样式。。。

    4、实现效果:

    5、具体实现:

    import TimeManager from './TimeManager.js';
     
    export default class Bullet{
        
        elem;
        x;
        speedX=2;
        width;
     
        constructor(txt){
            this.elem = this.createElem(txt);
        }
        createElem(txt){
            if(this.elem) return
            let div = document.createElement("div");
            Object.assign(div.style,{
                position:"absolute",
                whiteSpace: "nowrap",
                fontSize:"16px",
                // color:"#000",
                color:"#e00",
            })
            div.textContent = txt;
            return div
        }
        appendTo(parent){
            if(typeof parent === "string") parent = document.querySelector(parent);
            parent.appendChild(this.elem);
            let rect = parent.getBoundingClientRect();
            this.elem.style.top = Math.random()*rect.height/4 +"px";
            this.width = this.elem.offsetWidth;
            this.x = rect.width;
            this.elem.style.left = this.x + "px";
            TimeManager.instance.add(this);
        }
        update(){
            if(!this.elem) return;
            this.x -= this.speedX;
            this.elem.style.left = this.x +"px";
            if(this.x<-this.width){
                this.elem.remove();
                TimeManager.instance.remove(this);
                this.elem = null;
            }
        }
    }
    export default class TimeManager{
        
        static _instance;
        list = new Set();
        ids;
     
        constructor(){
     
        }
        static get instance(){
            TimeManager._instance = TimeManager._instance? TimeManager._instance : new TimeManager();
            return TimeManager._instance;
        }
        add(elem){
            if(!elem) return
            if(elem.update) this.list.add(elem);
            if(!this.ids) this.ids = setInterval(()=>{
                this.update();
            },16);
        }
        remove(elem){
            if(!elem) return
            this.list.delete(elem);
            if(this.list.size===0 && this.ids){
                clearInterval(this.ids);
                this.ids=0;
            }
        }
        update(){
            this.list.forEach(item=>{
                item.update();
            })
        }
    }
    import Bullet from './Bullet.js';
     
    export default class Player extends EventTarget{
     
        static WIDTH=638;
        static HEIGHT=493;
        elem;
        input;
     
        constructor(path){
            super();
            this.elem = this.createElem(path);
            document.addEventListener("keyup",e=>this.keyHandler(e));
        }
        keyHandler(e){
            if(e.keyCode !== 13) return;
            if(this.input.value.trim().length===0) return;
            let b = new Bullet(this.input.value);
            b.appendTo(this.elem);
            this.input.value = "";
        }
        appendTo(parent){
            if(typeof parent==="string") parent = document.querySelector(parent);
            parent.appendChild(this.elem);
        }
        createElem(path){
            // 播放器最外层容器
            let player = document.createElement("div");
            player.className = "player";
            Object.assign(player.style,{
                width:Player.WIDTH+"px",
                height:Player.HEIGHT+"px",
                userSelect:"none",
                overflow: "hidden",
                position:"relative",
                verticalAlign:"baseline",
            })
            // 播放器视频播放部分:应包括顶部作者和反馈栏、视频状态按钮、视频展示部分。。。。
            let videoWrap = document.createElement("div");
            Object.assign(videoWrap.style,{
                width:"100%",
                height:"447px",
                backgroundColor:"#000",
                position:"relative",
                top:0,
                display:"flex",
                flexDirection:"column",
            })
            // 创建播放器上层:包括标题,作者,反馈意见和举报等。。。。
            let videoTop = document.createElement("div");
            Object.assign(videoTop.style,{
                width:"100%",
                height:"42px",
                position:"relative",
                top:"0px",
                left:"0px",
                opacity:"0",
                color:"#fff",
                pointerEvents:"none",
                // transition: "all .2s ease-in-out",
                transition: "all .2s",
            })
            // 视频播放状态开关
            // let videoState = document.createElement("div");
            // 视频播放部分
            let videoContent = document.createElement("div");
            Object.assign(videoContent.style,{
                width:"100%",
                // height:"100%",
                height:"361px",
                position:"relative",
                userSelect:"none",
            })
            let video = document.createElement("video");
            video.src = path;
            video.controls = "controls";
            video.preload = "auto";
            Object.assign(video.style,{
                // 视频居中:进度条被拉长,但是视频不会被拉长,直接居中:
                height:"100%",
                width:"100%",
            })
            videoContent.appendChild(video);
     
            // 视频播放和弹幕滚动控制栏:清晰度/倍速/循环/镜像/宽屏/网页全屏/进度条等、、、、、
            let videoControlWrap = document.createElement("div");
            Object.assign(videoControlWrap.style,{
                width:"100%",
                height:"44px",
                opacity:"0",
                position:"relative",
                bottom:"0",
            })
     
            // 底部发送弹幕及设置发送弹幕样式:例如弹幕颜色/字号/滚动/悬停/速度/字体/屏蔽等。。。
            let bottomArea = document.createElement("div");
            Object.assign(bottomArea.style,{
                width:"100%",
                height:"46px",
            })
            this.input = document.createElement("input");
            Object.assign(this.input.style,{
                width:"130px",
                height:"30px",
                color:"#212121",
                // border:"0px",
                lineHeight:"30px",
                boxSizing: "border-box",
                minWidth: "115px",
                padding:"0 5px",
                fontSize:"12px",
                border:"1px solid #e7e7e7",    //外框样式:
                backgroundColor:"#f4f4f4",
            })
            bottomArea.appendChild(this.input);
     
            videoWrap.appendChild(videoTop);
            videoWrap.appendChild(videoContent);
            videoWrap.appendChild(videoControlWrap);
     
            player.appendChild(videoWrap);
            player.appendChild(bottomArea);
            return player;
        }
    }
    <!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>
        </style>
    </head>
    <body>
        <script type="module">
            import Player from './js/Player.js';
            import TimeManager from './js/TimeManager.js';
            import Bullet from './js/Bullet.js';
     
            // 播放器使用
            let player = new Player("./test3.mp4");
            player.appendTo("body");
     
        </script>
    </body>
    </html>

    以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持IIS7站长之家博文。