From d12f04c7aa849e166084af9786542619ab27b8fb Mon Sep 17 00:00:00 2001 From: 18278715334 <18278715334@163.com> Date: Mon, 8 Dec 2025 16:33:48 +0800 Subject: [PATCH] =?UTF-8?q?=E5=BC=B9=E5=B9=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/common/DanmakuBar.vue | 85 ++++++++++++++++++---------- 1 file changed, 56 insertions(+), 29 deletions(-) diff --git a/src/components/common/DanmakuBar.vue b/src/components/common/DanmakuBar.vue index 24840a1..76dc111 100644 --- a/src/components/common/DanmakuBar.vue +++ b/src/components/common/DanmakuBar.vue @@ -26,6 +26,7 @@ animationDuration: `${danmaku.duration}ms`, animationDelay: `${danmaku.delay}ms` }" + @animationend="handleAnimationEnd(danmaku.id)" >
{{ danmaku.companyName || '未知企业' }} @@ -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; } }