Files
product-uniapp/components/danmu/danmu.vue
T
2025-12-22 11:44:02 +08:00

147 lines
3.1 KiB
Vue

<template>
<view class="danmu-container" v-if="visible">
<view
v-for="item in danmuItems"
:key="item.id"
class="danmu-item"
:style="{
top: item.top + 'rpx',
animationDuration: item.speed + 's',
color: item.color
}"
@animationend="finishDanmu(item.id, item.lane)"
>
{{ item.text }}
</view>
</view>
</template>
<script>
export default {
props: {
list: Array,
visible: { type: Boolean, default: true },
row: { type: Number, default: 5 } // 轨道数
},
data() {
return {
danmuItems: [],
laneBusy: [], // 轨道是否被占用
pendingQueue: [] // 等待队列
}
},
mounted() {
this.laneBusy = Array(this.row).fill(false)
this.startDanmu()
},
methods: {
startDanmu() {
let index = 0
setInterval(() => {
if (this.list && this.list.length > 0) {
const text = this.list[index].content
this.createDanmu(text)
index = (index + 1) % this.list.length
}
}, 2200)
},
createDanmu(text) {
const lane = this.getFreeLane()
// 如果没有空闲轨道,加入等待队列
if (lane === -1) {
this.pendingQueue.push(text)
return
}
const id = Date.now() + Math.random()
const item = {
id,
text,
top: lane * 80 + 20, // 每条轨道高度 80rpx,顶部留20rpx间距
speed: 14 + Math.random()*6,
color: this.randomColor(),
lane
}
this.danmuItems.push(item)
},
getFreeLane() {
// 找到第一个空轨道
for (let i = 0; i < this.row; i++) {
if (!this.laneBusy[i]) {
this.laneBusy[i] = true
return i
}
}
// 如果都满了,返回-1,不创建弹幕
return -1
},
finishDanmu(id, lane) {
// 移除弹幕项
this.danmuItems = this.danmuItems.filter(i => i.id !== id)
// 释放轨道
if (lane !== undefined && lane >= 0) {
this.laneBusy[lane] = false
// 检查等待队列,如果有等待的弹幕,立即创建
if (this.pendingQueue.length > 0) {
const text = this.pendingQueue.shift()
this.$nextTick(() => {
this.createDanmu(text)
})
}
}
},
randomColor() {
const colors = ["#fff", "#00F6FF", "#FFEA00", "#FF66C4"]
return colors[Math.floor(Math.random() * colors.length)]
}
}
}
</script>
<style>
.danmu-container {
position: absolute;
left: 0;
top: 450rpx;
width: 100%;
height: 600rpx;
overflow: hidden;
pointer-events: none;
z-index: 100;
}
.danmu-item {
position: absolute;
right: -400rpx;
font-size: 26rpx;
white-space: nowrap;
animation-name: danmu-move;
animation-timing-function: linear;
animation-fill-mode: forwards;
background: rgb(0 0 0 / 60%);
padding: 5px 14px;
border-radius: 20px;
line-height: 1.5;
max-width: 600rpx;
overflow: hidden;
text-overflow: ellipsis;
}
@keyframes danmu-move {
from { transform: translateX(0); }
to { transform: translateX(-150vw); }
}
</style>