vue3-danmaku
Version:
基于 Vue3 的弹幕交互组件
2 lines (1 loc) • 6.93 kB
JavaScript
import{computed as e,defineComponent as t,ref as n,reactive as a,onMounted as l,onBeforeUnmount as u,nextTick as s,createApp as o,h as d,openBlock as i,createElementBlock as r,createElementVNode as m,normalizeClass as c,renderSlot as v}from"vue";var p=t({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:i,slots:r}){let m=n(document.createElement("div")),c=n(document.createElement("div"));const v=n(0),p=n(0);let f=0;const h=n(0),y=n(0),g=n(0),b=n(!1),k=n(!1),x=n({}),w=function(t,n,a="modelValue",l){return e({get:()=>t[a],set:e=>{n(`update:${a}`,l?l(e):e)}})}(t,i,"danmus"),S=a({channels:e((()=>t.channels||h.value)),autoplay:e((()=>t.autoplay)),loop:e((()=>t.loop)),useSlot:e((()=>t.useSlot)),debounce:e((()=>t.debounce)),randomChannel:e((()=>t.randomChannel))}),C=a({height:e((()=>y.value)),fontSize:e((()=>t.fontSize)),speeds:e((()=>t.speeds)),top:e((()=>t.top)),right:e((()=>t.right))});function N(){E(),t.isSuspend&&function(){let e=[];c.value.addEventListener("mouseover",(t=>{let n=t.target;n.className.includes("dm")||(n=n.closest(".dm")||n),n.className.includes("dm")&&(e.includes(n)||(i("dm-over",{el:n}),n.classList.add("pause"),e.push(n)))})),c.value.addEventListener("mouseout",(t=>{let n=t.target;n.className.includes("dm")||(n=n.closest(".dm")||n),n.className.includes("dm")&&(i("dm-out",{el:n}),n.classList.remove("pause"),e.forEach((e=>{e.classList.remove("pause")})),e=[])}))}(),S.autoplay&&L()}function E(){if(v.value=m.value.offsetWidth,p.value=m.value.offsetHeight,0===v.value||0===p.value)throw new Error("获取不到容器宽高")}function L(){k.value=!1,f||(f=window.setInterval((()=>function(){if(!k.value&&w.value.length)if(g.value>w.value.length-1){const e=c.value.children.length;S.loop&&(e<g.value&&(i("list-end"),g.value=0),B())}else B()}()),S.debounce))}function B(e){const n=S.loop?g.value%w.value.length:g.value,a=e||w.value[n];let l=document.createElement("div");S.useSlot?l=function(e,t){const n=o({render:()=>d("div",{},[r.dm&&r.dm({danmu:e,index:t})])});return n.mount(document.createElement("div"))}(a,n).$el:(l.innerHTML=a,l.setAttribute("style",t.extraStyle),l.style.fontSize=`${C.fontSize}px`,l.style.lineHeight=`${C.fontSize}px`),l.classList.add("dm"),c.value.appendChild(l),l.style.opacity="0",s((()=>{C.height||(y.value=l.offsetHeight),S.channels||(h.value=Math.floor(p.value/(C.height+C.top)));let e=function(e){let t=[...Array(S.channels).keys()];S.randomChannel&&(t=t.sort((()=>.5-Math.random())));for(let n of t){const t=x.value[n];if(!t||!t.length)return x.value[n]=[e],e.addEventListener("animationend",(()=>x.value[n].splice(0,1))),n%S.channels;for(let a=0;a<t.length;a++){const l=$(t[a])-10;if(l<=.88*(e.offsetWidth-t[a].offsetWidth)||l<=0)break;if(a===t.length-1)return x.value[n].push(e),e.addEventListener("animationend",(()=>x.value[n].splice(0,1))),n%S.channels}}return-1}(l);if(e>=0){const t=l.offsetWidth,a=C.height;l.classList.add("move"),l.dataset.index=`${n}`,l.dataset.channel=e.toString(),l.style.opacity="1",l.style.top=e*(a+C.top)+"px",l.style.width=t+C.right+"px",l.style.setProperty("--dm-scroll-width",`-${v.value+t}px`),l.style.left=`${v.value}px`,l.style.animationDuration=v.value/C.speeds+"s",l.addEventListener("animationend",(()=>{Number(l.dataset.index)!==w.value.length-1||S.loop||i("play-end",l.dataset.index),c.value&&c.value.removeChild(l)})),g.value++}else c.value.removeChild(l)}))}function $(e){const t=e.offsetWidth||parseInt(e.style.width),n=e.getBoundingClientRect().right||c.value.getBoundingClientRect().right+t;return c.value.getBoundingClientRect().right-n}function z(){clearInterval(f),f=0,g.value=0}return l((()=>{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".'),N()})),u((()=>{z()})),{container:m,dmContainer:c,hidden:b,paused:k,danmuList:w,getPlayState:function(){return!k.value},resize:function(){E();const e=c.value.getElementsByClassName("dm");for(let t=0;t<e.length;t++){const n=e[t];n.style.setProperty("--dm-scroll-width",`-${v.value+n.offsetWidth}px`),n.style.left=`${v.value}px`,n.style.animationDuration=v.value/C.speeds+"s"}},play:L,pause:function(){k.value=!0},stop:function(){x.value={},c.value.innerHTML="",k.value=!0,b.value=!1,z()},show:function(){b.value=!1},hide:function(){b.value=!0},reset:function(){y.value=0,N()},add:function(e){if(g.value===w.value.length)return w.value.push(e),w.value.length-1;{const t=g.value%w.value.length;return w.value.splice(t,0,e),t+1}},push:function(e){return w.value.push(e),w.value.length-1},insert:B}}});const f={ref:"container",class:"vue-danmaku"};!function(e,t){void 0===t&&(t={});var n=t.insertAt;if(e&&"undefined"!=typeof document){var a=document.head||document.getElementsByTagName("head")[0],l=document.createElement("style");l.type="text/css","top"===n&&a.firstChild?a.insertBefore(l,a.firstChild):a.appendChild(l),l.styleSheet?l.styleSheet.cssText=e:l.appendChild(document.createTextNode(e))}}(".vue-danmaku {\n position: relative;\n overflow: hidden;\n}\n.vue-danmaku .danmus {\n position: absolute;\n left: 0;\n top: 0;\n width: 100%;\n height: 100%;\n opacity: 0;\n -webkit-transition: all 0.3s;\n transition: all 0.3s;\n}\n.vue-danmaku .danmus.show {\n opacity: 1;\n}\n.vue-danmaku .danmus.paused .dm.move {\n animation-play-state: paused;\n}\n.vue-danmaku .danmus .dm {\n position: absolute;\n font-size: 20px;\n color: #ddd;\n white-space: pre;\n transform: translateX(0);\n transform-style: preserve-3d;\n}\n.vue-danmaku .danmus .dm.move {\n will-change: transform;\n animation-name: moveLeft;\n animation-timing-function: linear;\n animation-play-state: running;\n}\n.vue-danmaku .danmus .dm.pause {\n animation-play-state: paused;\n z-index: 100;\n}\n@keyframes moveLeft {\n from {\n transform: translateX(0);\n }\n to {\n transform: translateX(var(--dm-scroll-width));\n }\n}\n@-webkit-keyframes moveLeft {\n from {\n -webkit-transform: translateX(0);\n }\n to {\n -webkit-transform: translateX(var(--dm-scroll-width));\n }\n}"),p.render=function(e,t,n,a,l,u){return i(),r("div",f,[m("div",{ref:"dmContainer",class:c(["danmus",{show:!e.hidden},{paused:e.paused}])},null,2),v(e.$slots,"default")],512)},p.__file="src/lib/Danmaku.vue";export{p as default};