vue弹幕实现不重叠
实现不重叠的 Vue 弹幕功能
核心思路
通过动态计算每条弹幕的垂直位置,确保新弹幕不会与已有弹幕在垂直方向上重叠。需要结合轨道管理、碰撞检测和动画控制。

轨道管理法
将屏幕垂直划分为多条虚拟轨道,每条轨道同一时间只允许一条弹幕存在。新弹幕优先选择空闲轨道。

// 轨道状态管理
data() {
return {
tracks: [false, false, false], // 假设3条轨道
danmuList: []
}
},
methods: {
addDanmu(text) {
const trackIndex = this.tracks.findIndex(used => !used);
if (trackIndex >= 0) {
this.tracks[trackIndex] = true;
this.danmuList.push({
text,
track: trackIndex,
id: Date.now()
});
}
},
clearTrack(trackIndex) {
this.tracks[trackIndex] = false;
}
}
动态位置计算法
实时计算每条弹幕的占据区域,通过位置检测避免重叠。
// 弹幕位置检测
isPositionAvailable(yPos) {
return !this.danmuList.some(item => {
const itemTop = item.top;
const itemBottom = item.top + item.height;
return (yPos >= itemTop && yPos <= itemBottom) ||
(itemTop >= yPos && itemTop <= yPos + height);
});
}
CSS 实现方案
结合 CSS 动画和轨道定位,确保弹幕在不同层级移动。
.danmu-track {
position: absolute;
height: 30px;
width: 100%;
}
.track-1 { top: 10%; }
.track-2 { top: 40%; }
.track-3 { top: 70%; }
.danmu-item {
position: absolute;
white-space: nowrap;
animation: move linear;
animation-duration: 8s;
}
@keyframes move {
from { transform: translateX(100%); }
to { transform: translateX(-100%); }
}
性能优化建议
- 使用
requestAnimationFrame控制动画流畅度 - 对弹幕 DOM 进行虚拟滚动优化
- 限制同时显示的弹幕数量
- 采用 Canvas 渲染替代 DOM 方案(适用于大量弹幕)
完整组件示例
<template>
<div class="danmu-container">
<div
v-for="(item, index) in activeList"
:key="item.id"
:class="`danmu-item track-${item.track}`"
@animationend="handleAnimationEnd(item)"
>
{{ item.text }}
</div>
</div>
</template>
<script>
export default {
data() {
return {
maxTracks: 3,
tracks: Array(3).fill(false),
danmuQueue: [],
activeList: []
}
},
methods: {
addDanmu(text) {
const track = this.findAvailableTrack();
if (track !== -1) {
this.activeList.push({
id: Date.now(),
text,
track
});
} else {
this.danmuQueue.push(text);
}
},
findAvailableTrack() {
return this.tracks.findIndex(used => !used);
},
handleAnimationEnd(item) {
this.tracks[item.track] = false;
this.activeList = this.activeList.filter(i => i.id !== item.id);
if (this.danmuQueue.length > 0) {
this.addDanmu(this.danmuQueue.shift());
}
}
}
}
</script>






