This commit is contained in:
2025-12-08 17:05:04 +08:00
parent 840e4b467f
commit 1c81b4f081

View File

@@ -16,7 +16,7 @@
<span class="text-xs text-gray-500">{{ enabled ? '开启' : '关闭' }}</span>
</div>
</div>
<div ref="danmakuWrapper" class="relative flex-1 overflow-hidden" style="min-height: 80px; max-height: 100px;">
<div ref="danmakuWrapper" class="relative flex-1 overflow-hidden" style="min-height: 120px; max-height: 140px;">
<div
v-for="danmaku in activeDanmakus"
:key="danmaku.id"
@@ -169,6 +169,12 @@ const processPendingQueue = () => {
isProcessing.value = true
const processNext = () => {
// 如果有弹幕实体还在当前弹幕区域内,则等待其完全离开后再装载下一条
if (hasDanmakuInside()) {
setTimeout(processNext, 300)
return
}
if (pendingQueue.value.length === 0) {
isProcessing.value = false
return
@@ -177,8 +183,8 @@ const processPendingQueue = () => {
const item = pendingQueue.value.shift()
addDanmakuToQueue(item)
// 计算下一个弹幕的延迟1.5秒 + 0-2秒随机
const delay = 1500 + Math.random() * 2000
// 计算下一个弹幕的延迟1秒 + 0-1秒随机
const delay = 1000 + Math.random() * 1000
setTimeout(() => {
processNext()
@@ -198,12 +204,11 @@ const checkCollision = (newDanmaku) => {
const newBottom = newTop + danmakuHeight
// 检查与所有活动弹幕的垂直位置碰撞
// 由于弹幕从右侧进入,主要检查垂直位置是否重叠
for (const existingDanmaku of activeDanmakus.value) {
const existingTop = existingDanmaku.top
const existingBottom = existingTop + danmakuHeight
// 检查垂直位置是否太接近(考虑最小间距)
// 垂直位置是否太接近(考虑最小间距)
const verticalOverlap = !(newBottom < existingTop - minVerticalGap || newTop > existingBottom + minVerticalGap)
if (verticalOverlap) {
@@ -268,6 +273,7 @@ const addDanmakuToQueue = (item) => {
return
}
// 暂存队列(保持逻辑完整,便于未来扩展)
danmakuQueue.value.push(danmaku)
// 如果队列中的弹幕太多,移除最旧的
@@ -275,8 +281,20 @@ const addDanmakuToQueue = (item) => {
danmakuQueue.value.shift()
}
// 添加到活动弹幕列表
// 仅在右侧区域空闲时添加
if (!hasDanmakuInside()) {
activeDanmakus.value.push(danmaku)
} else {
// 如果右侧区域有弹幕,稍后再尝试
const tryAdd = () => {
if (!hasDanmakuInside()) {
activeDanmakus.value.push(danmaku)
} else {
setTimeout(tryAdd, 200)
}
}
setTimeout(tryAdd, 200)
}
// 弹幕会在动画结束时通过 animationend 事件自动移除
}
@@ -285,6 +303,26 @@ const addDanmakuToQueue = (item) => {
const handleAnimationEnd = (id) => {
// 动画结束后,弹幕已经完全移出左侧,可以安全移除
removeDanmaku(id)
// 释放占用,继续处理待排队的弹幕
isProcessing.value = false
processPendingQueue()
}
// 判断当前弹幕区域内是否还有弹幕实体(交叠到可视区域)
const hasDanmakuInside = () => {
if (!danmakuWrapper.value) return false
const wrapperRect = danmakuWrapper.value.getBoundingClientRect()
const elements = danmakuWrapper.value.querySelectorAll('.danmaku-item')
for (const el of elements) {
const rect = el.getBoundingClientRect()
// 判断是否与可视区域有交叠(水平和垂直都需有重叠)
const horizontalOverlap = rect.right > wrapperRect.left && rect.left < wrapperRect.right
const verticalOverlap = rect.bottom > wrapperRect.top && rect.top < wrapperRect.bottom
if (horizontalOverlap && verticalOverlap) {
return true
}
}
return false
}
// 计算弹幕的垂直位置(随机分散,避免重叠)