This commit is contained in:
2025-12-08 16:33:48 +08:00
parent a5b516d42b
commit d12f04c7aa

View File

@@ -26,6 +26,7 @@
animationDuration: `${danmaku.duration}ms`,
animationDelay: `${danmaku.delay}ms`
}"
@animationend="handleAnimationEnd(danmaku.id)"
>
<div :class="['danmaku-content', `danmaku-content-${danmaku.status}`]">
<span :class="['company-name', `company-name-${danmaku.status}`]">{{ danmaku.companyName || '未知企业' }}</span>
@@ -154,13 +155,14 @@ const addDanmakuToQueue = (item) => {
startAt: item.start_at || item.created_at,
timeAgo: calculateTimeAgo(item.start_at || item.created_at),
top: 0,
duration: props.danmakuSpeed,
duration: 0, // 将在添加到DOM后计算
delay: 0
}
// 计算垂直位置(避免重叠)
// 计算垂直位置(随机分散,避免重叠)
danmaku.top = calculateTopPosition()
danmaku.delay = Math.random() * 500 // 随机延迟0-500ms,让弹幕错开
// 增加随机延迟,让弹幕错开时间出现0-2000ms
danmaku.delay = Math.random() * 2000
danmakuQueue.value.push(danmaku)
@@ -169,41 +171,66 @@ const addDanmakuToQueue = (item) => {
danmakuQueue.value.shift()
}
// 添加到活动弹幕列表
activeDanmakus.value.push(danmaku)
// 弹幕动画结束后移除
// 延迟添加弹幕,让它们错开时间出现
setTimeout(() => {
removeDanmaku(danmaku.id)
}, danmaku.duration + danmaku.delay + 1000)
// 使用固定的动画时间,确保弹幕完全移出左侧
// translateX(-200%) 意味着向左移动自身宽度的200%,应该足够移出容器
danmaku.duration = props.danmakuSpeed
activeDanmakus.value.push(danmaku)
// 弹幕会在动画结束时通过 animationend 事件自动移除
}, danmaku.delay)
}
// 计算弹幕的垂直位置(只显示两行,垂直居中)
// 处理动画结束事件
const handleAnimationEnd = (id) => {
// 动画结束后,弹幕已经完全移出左侧,可以安全移除
removeDanmaku(id)
}
// 计算弹幕的垂直位置(随机分散,避免重叠)
const calculateTopPosition = () => {
const maxLines = 2 // 最多显示两行
const containerHeight = 80 // 容器高度80px
const lineHeight = 40 // 每行高度40px
const totalHeight = maxLines * lineHeight // 两行总高度80px
const startTop = (containerHeight - totalHeight) / 2 // 垂直居中起始位置
const minTop = 10 // 最小顶部距离
const maxTop = containerHeight - 40 // 最大顶部距离(留出弹幕高度空间)
// 计算当前有多少条弹幕
const currentCount = activeDanmakus.value.length
// 获取当前活动的弹幕位置
const activePositions = activeDanmakus.value.map(d => d.top).filter(pos => pos > 0)
// 如果已经有两条或更多,移除最旧的,保持在两行
if (currentCount >= maxLines) {
// 移除最旧的弹幕
const oldestDanmaku = activeDanmakus.value[0]
if (oldestDanmaku) {
removeDanmaku(oldestDanmaku.id)
// 尝试找到一个不重叠的位置
let newTop
let attempts = 0
const minGap = 35 // 最小间距35px
do {
// 在容器高度范围内随机生成位置
newTop = minTop + Math.random() * (maxTop - minTop)
attempts++
// 检查是否与现有弹幕重叠
const tooClose = activePositions.some(pos => Math.abs(pos - newTop) < minGap)
if (!tooClose || attempts > 10) {
break
}
} while (attempts < 10)
// 如果尝试10次还是重叠就使用一个固定但分散的位置
if (attempts >= 10) {
const positions = [20, 50] // 两行固定位置
const usedPositions = activePositions.filter(pos =>
positions.some(fixedPos => Math.abs(pos - fixedPos) < minGap)
)
if (usedPositions.length < positions.length) {
newTop = positions.find(pos =>
!activePositions.some(used => Math.abs(used - pos) < minGap)
) || positions[0]
} else {
newTop = minTop + Math.random() * (maxTop - minTop)
}
}
// 计算新弹幕的位置(两行垂直居中)
if (activeDanmakus.value.length === 0) {
return startTop // 第一条从居中位置开始
} else {
return startTop + lineHeight // 第二条在下一行
}
return Math.round(newTop)
}
// 移除弹幕
@@ -295,7 +322,7 @@ onUnmounted(() => {
opacity: 1;
}
to {
transform: translateX(-200%);
transform: translateX(-300%);
opacity: 1;
}
}