vue弹幕实现不重叠
Vue弹幕不重叠实现方法
使用CSS定位与随机轨道
通过预设多条水平轨道(CSS定位),每条弹幕在固定轨道上运行,避免垂直方向重叠。动态生成弹幕时随机分配空闲轨道。
<template>
<div class="danmu-container">
<div
v-for="(item, index) in danmuList"
:key="index"
:class="`danmu-item track-${item.track}`"
>
{{ item.text }}
</div>
</div>
</template>
<style>
.danmu-container {
position: relative;
height: 300px;
overflow: hidden;
}
.danmu-item {
position: absolute;
white-space: nowrap;
animation: move linear;
}
.track-0 { top: 10%; }
.track-1 { top: 30%; }
.track-2 { top: 50%; }
.track-3 { top: 70%; }
@keyframes move {
from { transform: translateX(100%); }
to { transform: translateX(-100%); }
}
</style>
碰撞检测算法
实时计算弹幕元素的位置和速度,通过检测元素边界矩形是否相交来判断碰撞。发现碰撞时调整新弹幕的发射时间或轨道。
function checkCollision(newDanmu, existingDanmus) {
const newRect = {
left: window.innerWidth,
right: window.innerWidth + newDanmu.width,
top: newDanmu.track * 30,
bottom: newDanmu.track * 30 + 20
};
return existingDanmus.some(danmu => {
const danmuRect = {
left: danmu.left,
right: danmu.left + danmu.width,
top: danmu.track * 30,
bottom: danmu.track * 30 + 20
};
return !(
newRect.right < danmuRect.left ||
newRect.left > danmuRect.right ||
newRect.bottom < danmuRect.top ||
newRect.top > danmuRect.bottom
);
});
}
时间间隔控制
通过队列管理弹幕发射,设置最小时间间隔保证同一轨道上的弹幕不会连续出现。结合requestAnimationFrame实现平滑渲染。
const trackTimers = [0, 0, 0, 0];
function addDanmu(text) {
const now = performance.now();
const availableTrack = trackTimers.findIndex(
time => now - time > 2000
);
if (availableTrack !== -1) {
trackTimers[availableTrack] = now;
danmuList.push({
text,
track: availableTrack
});
}
}
动态轨道数量
根据容器高度和字体大小自动计算最大轨道数,响应式调整布局。使用ResizeObserver监听容器尺寸变化。
const calculateTracks = () => {
const container = document.querySelector('.danmu-container');
const lineHeight = 24;
return Math.floor(container.clientHeight / lineHeight);
};
性能优化
使用虚拟滚动技术,对离开可视区域的弹幕进行回收。通过CSS will-change属性提升动画性能,避免重绘和回流。
.danmu-item {
will-change: transform;
contain: content;
}
完整组件示例
结合上述技术的Vue组件实现,包含弹幕速度控制、暂停恢复等功能。
<script setup>
import { ref, onMounted } from 'vue';
const danmuList = ref([]);
const tracks = ref(4);
const speed = ref(10);
function launchDanmu(text) {
let track = Math.floor(Math.random() * tracks.value);
danmuList.value.push({
id: Date.now(),
text,
track,
animationDuration: `${speed.value}s`
});
}
</script>
以上方法可根据实际需求组合使用,CSS轨道方案适合简单场景,碰撞检测适合高精度需求,时间间隔控制平衡性能和效果。







