最新版本V3.2.5增加了图片弹幕类型,修改了demo展示页面,调整了部分代码。具体可以参考git中的CHANGELOG.md和README.md文章,主要讲实现方法和设计思路,所以部分接口还是老版本接口。最新的接口请到git查看前言。说实话,第二版到现在已经半年了。我想我可能写不出第三版了。顶多重构一下第二版的代码。出乎意料的是,用了大约一个星期的时间继续写第三版。主要是第二版的播放器模块和弹幕模块的耦合太严重了,和我想要的效果相去甚远,所以继续写第三版。这次代码会更轻。我去掉了播放器模块,扩大了插件的适用范围,让我有点意外的是弹幕系统的性能在写第三版的过程中得到了进一步的提升,可以说是额外的惊喜。由于我用ES6语法写的第三版,兼容性不是很好(是的,我只针对IE),即使我用babel转ES5,IE还是有毒,目前支持IE10+。所以后面会花点时间写一个ES5完全兼容的版本,不考虑IE或者只是对源码感兴趣的小伙伴可以尽情使用。github:githubAPI接口都在git里面。文章不会介绍插件使用相关的内容,仅对部分源码和设计思路进行说明。如果觉得插件还行,请给git一个star,谢谢demo:我是demo注:我demo好像有些人不知道怎么操作。简单介绍一下基本操作:所有发布的功能项都可以通过下拉框进行切换,目前包括“添加普通弹幕”、“添加高级弹幕”、“筛选”、“添加全局样式”、“ControlItems”,添加普通弹幕和添加高级弹幕只是添加数据,不会运行插件,需要跳转到“ControlItems”点击启动,然后等待弹幕的到来outtoadvanced弹幕的动画属于排队动画。需要“将修改后的数据保存为第n步”(n至少为1),然后点击确定,添加过滤功能。最简单的"type":"slide",表示过滤所有滚动弹幕,或者"text":"string"表示过滤所有包含字符串的弹幕。可以先开局再加弹幕。同样的道理。那些不需要太多代码的东西的源码都是按照操作顺序来的。总共由5部分组成:普通弹幕类、高级弹幕类、主程序类、封装输出函数、Tween算法类,第四和第五部分比较简单,第五部分是原始Tween算法,以及第四部分是对所有内部接口进行过滤,选择性地暴露一些我想暴露的内部功能接口,并提供一个外部接口,增加一点稳定性。源码如下:letDanMuer=function(wrapper,opts){letproxyDMer=newProxy(newDMer(wrapper,opts),{get:function(target,key){if(typeoftarget[key]==“函数”)返回目标[键].bind(目标);返回目标[键];}});//确保this指向原始对象letDM=proxyDMer;//选择性暴露一些接口return{pause:DM.pause,//暂停run:DM.run,//继续启动:DM.start,//运行stop:DM.stop,//停止changeStyle:DM.changeStyle,//修改普通弹幕全局样式addGradient:DM.addGradient,//普通弹幕渐变setSize:DM.setSize,//修改宽高inputData:DM.inputData,//给普通弹幕插入数据inputEffect:DM.inputEffect,//向高级弹幕插入清除数据:DM.clear,//清除所有弹幕重置:DM.reset,//从某个弹幕重新开始addFilter:DM.addFilter,//添加过滤器removeFilter:DM.removeFilter,//删除过滤器disableEffect:DM.disableEffect,//不开启高级弹幕enableEffect:DM.enableEffect,//开启高级弹幕getSize:DM.getSize,//获取宽高,getFPS:DM.getFPS//获取fps};};//提供外部参考接口if(typeofmodule!='undefined'&&module.exports){module.exports=DanMuer;}elseif(typeofdefine=="function"&&define.amd){define(function(){returnDanMuer;});}else{window.DanMuer=DanMuer;}第三部分属于入门类,其实每一个时间调用插件会先实例化第三部分。这里主要保存了一些暴露的API接口,以及插件初始化函数、事件函数和主循环函数,用于对插件进行整体控制。部分源码如下://Initializeconstructor(wrap,opts={}){if(!wrap){thrownewError("Thecorrectwrapperisnotset");}//数据this.wrapper=wrap;this.width=wrap.clientWidth;这个.height=wrap.clientHeight;this.canvas=document.createElement("canvas");this.canvas2=document.createElement("canvas");this.normal=newnormalDM(this.canvas,opts);//这里是普通弹幕对象this.effect=neweffectDM(this.canvas2,opts);//这里是高级弹幕对象this.name=opts.name||"";//没用this.fps=0;//状态这个.drawing=opts.auto||错误的;this.startTime=newDate().getTime();//fn这个[初始化]();这个[循环]();如果(opts.enableEvent)this.initEvent(opts);}[init](){//生成对应的canvasthis.canvas.style.cssText="position:absolute;z-index:100;top:0px;left:0px;";this.canvas2.style.cssText="position:absolute;z-index:101;top:0px;left:0px;";这个.setSize();this.wrapper.appendChild(this.canvas);this.wrapper.appendChild(this.canvas2);}//loop[loop](normal=this.normal,effect=this.effect,prev=this.startTime){letnow=newDate().getTime();如果(!this.drawing){normal.clearRect();effect.clearRect();返回假;}else{让[w,h,time]=[this.width,this.height,now-prev];this.fps=1000/次>>0;//这里进行内部的循环操作normal.update(w,h,time);effect.update(w,h,time);}requestAnimationFrame(()=>{this[loop](normal,effect,now);});}//主要对鼠标右键进行绑定initEvent(opts){let[el,normal,searching]=[this.canvas2,this.normal,false];el.onmouseup=function(e){e=e||事件;如果(搜索)返回假;搜索=真;if(e.button==2){让[pos,result]=[e.target.getBoundingClientRect(),""];让[x,y,i,items,item]=[e.clientX-pos.left,e.clientY-pos.top,0,normal.save];for(;item=items[i++];){让[ix,iy,w,h]=[item.x,item.y,item.width+10,item.height];如果(x
