2
This commit is contained in:
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user