This commit is contained in:
2025-12-08 16:45:22 +08:00
parent dad278fe15
commit 840e4b467f

View File

@@ -20,6 +20,7 @@
<div
v-for="danmaku in activeDanmakus"
:key="danmaku.id"
:data-danmaku-id="danmaku.id"
:class="['danmaku-item', `danmaku-${danmaku.status}`]"
:style="{
top: `${danmaku.top}px`,
@@ -187,7 +188,33 @@ const processPendingQueue = () => {
processNext()
}
// 添加弹幕到显示队列
// 检查弹幕碰撞(基于垂直位置和预计路径)
const checkCollision = (newDanmaku) => {
if (!danmakuWrapper.value) return false
const danmakuHeight = 40 // 弹幕高度
const minVerticalGap = 45 // 最小垂直间距(确保不重叠)
const newTop = newDanmaku.top
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) {
return true // 发生碰撞
}
}
return false
}
// 添加弹幕到显示队列(带碰撞检测)
const addDanmakuToQueue = (item) => {
const danmaku = {
id: item.id || `danmaku-${Date.now()}-${Math.random()}`,
@@ -199,11 +226,47 @@ const addDanmakuToQueue = (item) => {
timeAgo: calculateTimeAgo(item.start_at || item.created_at),
top: 0,
duration: props.danmakuSpeed,
delay: 0
delay: 0,
width: 0, // 将在DOM渲染后计算
currentLeft: 0 // 当前水平位置
}
// 计算垂直位置(随机分散,避免重叠)
danmaku.top = calculateTopPosition()
// 尝试找到一个不碰撞的位置
let attempts = 0
let foundPosition = false
while (attempts < 20 && !foundPosition) {
// 计算垂直位置
danmaku.top = calculateTopPosition()
// 检查碰撞
if (!checkCollision(danmaku)) {
foundPosition = true
break
}
attempts++
// 如果碰撞,稍微调整垂直位置
if (attempts < 10) {
// 尝试不同的垂直位置
continue
} else {
// 如果多次尝试都碰撞,延迟生成
setTimeout(() => {
addDanmakuToQueue(item)
}, 500 + Math.random() * 1000)
return
}
}
if (!foundPosition) {
// 如果找不到位置,延迟生成
setTimeout(() => {
addDanmakuToQueue(item)
}, 1000)
return
}
danmakuQueue.value.push(danmaku)
@@ -212,8 +275,9 @@ const addDanmakuToQueue = (item) => {
danmakuQueue.value.shift()
}
// 立即添加到活动弹幕列表
// 添加到活动弹幕列表
activeDanmakus.value.push(danmaku)
// 弹幕会在动画结束时通过 animationend 事件自动移除
}
@@ -348,12 +412,12 @@ onUnmounted(() => {
animation: danmaku-scroll linear forwards;
pointer-events: none;
will-change: transform;
transform: translateZ(0);
/* 弹幕从右侧隐藏区域开始(容器外),由动画控制位置 */
}
@keyframes danmaku-scroll {
from {
transform: translateX(0);
transform: translateX(100%);
opacity: 1;
}
to {