JS实现视频弹幕效果
程序员文章站
2022-03-16 20:50:53
使用es6的模块化开发及观察者模式来实现。观察者模式有很多种形式,这里是使用“注册—通知—撤销注册”的形式。timemanager类可以返回一个单例,每一条弹幕作为一个观察者,注册到timemanag...
使用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>
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。