vue3-danmaku
Version:
基于 Vue3 的弹幕交互组件
2 lines (1 loc) • 5.8 kB
JavaScript
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t(require("vue")):"function"==typeof define&&define.amd?define(["vue"],t):(e="undefined"!=typeof globalThis?globalThis:e||self).Vue3Danmaku=t(e.Vue)}(this,(function(e){"use strict";var t=e.defineComponent({name:"vue3-danmaku",components:{},props:{danmus:{type:Array,required:!0,default:()=>[]},channels:{type:Number,default:0},autoplay:{type:Boolean,default:!0},loop:{type:Boolean,default:!1},useSlot:{type:Boolean,default:!1},debounce:{type:Number,default:100},speeds:{type:Number,default:200},randomChannel:{type:Boolean,default:!1},fontSize:{type:Number,default:18},top:{type:Number,default:4},right:{type:Number,default:0},isSuspend:{type:Boolean,default:!1},extraStyle:{type:String,default:""}},emits:["list-end","play-end","dm-over","dm-out","update:danmus"],setup(t,{emit:n,slots:a}){let l=e.ref(document.createElement("div")),u=e.ref(document.createElement("div"));const o=e.ref(0),s=e.ref(0);let d=0;const i=e.ref(0),r=e.ref(0),c=e.ref(0),f=e.ref(!1),p=e.ref(!1),v=e.ref({}),m=function(t,n,a="modelValue",l){return e.computed({get:()=>t[a],set:e=>{n(`update:${a}`,l?l(e):e)}})}(t,n,"danmus"),h=e.reactive({channels:e.computed((()=>t.channels||i.value)),autoplay:e.computed((()=>t.autoplay)),loop:e.computed((()=>t.loop)),useSlot:e.computed((()=>t.useSlot)),debounce:e.computed((()=>t.debounce)),randomChannel:e.computed((()=>t.randomChannel))}),y=e.reactive({height:e.computed((()=>r.value)),fontSize:e.computed((()=>t.fontSize)),speeds:e.computed((()=>t.speeds)),top:e.computed((()=>t.top)),right:e.computed((()=>t.right))});function g(){b(),t.isSuspend&&function(){let e=[];u.value.addEventListener("mouseover",(t=>{let a=t.target;a.className.includes("dm")||(a=a.closest(".dm")||a),a.className.includes("dm")&&(e.includes(a)||(n("dm-over",{el:a}),a.classList.add("pause"),e.push(a)))})),u.value.addEventListener("mouseout",(t=>{let a=t.target;a.className.includes("dm")||(a=a.closest(".dm")||a),a.className.includes("dm")&&(n("dm-out",{el:a}),a.classList.remove("pause"),e.forEach((e=>{e.classList.remove("pause")})),e=[])}))}(),h.autoplay&&x()}function b(){if(o.value=l.value.offsetWidth,s.value=l.value.offsetHeight,0===o.value||0===s.value)throw new Error("获取不到容器宽高")}function x(){p.value=!1,d||(d=window.setInterval((()=>function(){if(!p.value&&m.value.length)if(c.value>m.value.length-1){const e=u.value.children.length;h.loop&&(e<c.value&&(n("list-end"),c.value=0),S())}else S()}()),h.debounce))}function S(l){const d=h.loop?c.value%m.value.length:c.value,f=l||m.value[d];let p=document.createElement("div");h.useSlot?p=function(t,n){const l=e.createApp({render:()=>e.h("div",{},[a.dm&&a.dm({danmu:t,index:n})])});return l.mount(document.createElement("div"))}(f,d).$el:(p.innerHTML=f,p.setAttribute("style",t.extraStyle),p.style.fontSize=`${y.fontSize}px`,p.style.lineHeight=`${y.fontSize}px`),p.classList.add("dm"),u.value.appendChild(p),p.style.opacity="0",e.nextTick((()=>{y.height||(r.value=p.offsetHeight),h.channels||(i.value=Math.floor(s.value/(y.height+y.top)));let e=function(e){let t=[...Array(h.channels).keys()];h.randomChannel&&(t=t.sort((()=>.5-Math.random())));for(let n of t){const t=v.value[n];if(!t||!t.length)return v.value[n]=[e],e.addEventListener("animationend",(()=>v.value[n].splice(0,1))),n%h.channels;for(let a=0;a<t.length;a++){const l=C(t[a])-10;if(l<=.88*(e.offsetWidth-t[a].offsetWidth)||l<=0)break;if(a===t.length-1)return v.value[n].push(e),e.addEventListener("animationend",(()=>v.value[n].splice(0,1))),n%h.channels}}return-1}(p);if(e>=0){const t=p.offsetWidth,a=y.height;p.classList.add("move"),p.dataset.index=`${d}`,p.dataset.channel=e.toString(),p.style.opacity="1",p.style.top=e*(a+y.top)+"px",p.style.width=t+y.right+"px",p.style.setProperty("--dm-scroll-width",`-${o.value+t}px`),p.style.left=`${o.value}px`,p.style.animationDuration=o.value/y.speeds+"s",p.addEventListener("animationend",(()=>{Number(p.dataset.index)!==m.value.length-1||h.loop||n("play-end",p.dataset.index),u.value&&u.value.removeChild(p)})),c.value++}else u.value.removeChild(p)}))}function C(e){const t=e.offsetWidth||parseInt(e.style.width),n=e.getBoundingClientRect().right||u.value.getBoundingClientRect().right+t;return u.value.getBoundingClientRect().right-n}function E(){clearInterval(d),d=0,c.value=0}return e.onMounted((()=>{console.error("%c [vue3-danmaku] ⚠️ DEPRECATION WARNING","background: #ffcc00; color: #000; padding: 2px 4px; border-radius: 3px; font-weight: bold;",'\n该包已停止维护,请迁移至新版官方库: "vue-danmaku"。\nThis package is deprecated. Please migrate to "vue-danmaku".'),g()})),e.onBeforeUnmount((()=>{E()})),{container:l,dmContainer:u,hidden:f,paused:p,danmuList:m,getPlayState:function(){return!p.value},resize:function(){b();const e=u.value.getElementsByClassName("dm");for(let t=0;t<e.length;t++){const n=e[t];n.style.setProperty("--dm-scroll-width",`-${o.value+n.offsetWidth}px`),n.style.left=`${o.value}px`,n.style.animationDuration=o.value/y.speeds+"s"}},play:x,pause:function(){p.value=!0},stop:function(){v.value={},u.value.innerHTML="",p.value=!0,f.value=!1,E()},show:function(){f.value=!1},hide:function(){f.value=!0},reset:function(){r.value=0,g()},add:function(e){if(c.value===m.value.length)return m.value.push(e),m.value.length-1;{const t=c.value%m.value.length;return m.value.splice(t,0,e),t+1}},push:function(e){return m.value.push(e),m.value.length-1},insert:S}}});const n={ref:"container",class:"vue-danmaku"};return t.render=function(t,a,l,u,o,s){return e.openBlock(),e.createElementBlock("div",n,[e.createElementVNode("div",{ref:"dmContainer",class:e.normalizeClass(["danmus",{show:!t.hidden},{paused:t.paused}])},null,2),e.renderSlot(t.$slots,"default")],512)},t.__file="src/lib/Danmaku.vue",t}));