js 实现弹幕
实现弹幕的基本思路
弹幕的核心是在屏幕上移动的文本元素,通常从右向左滚动。实现弹幕需要动态创建DOM元素,控制其移动和生命周期。
HTML结构准备
创建一个容器用于承载弹幕元素:

<div id="danmu-container" style="position: relative; width: 100%; height: 500px; overflow: hidden;"></div>
CSS样式设置
为弹幕元素添加基础样式:
.danmu-item {
position: absolute;
white-space: nowrap;
font-size: 20px;
color: #fff;
text-shadow: 1px 1px 2px #000;
}
JavaScript实现
创建弹幕类或函数管理弹幕行为:

class Danmu {
constructor(container) {
this.container = document.getElementById(container);
this.danmus = [];
}
// 添加新弹幕
add(text, options = {}) {
const danmu = document.createElement('div');
danmu.className = 'danmu-item';
danmu.textContent = text;
// 设置样式选项
if(options.color) danmu.style.color = options.color;
if(options.size) danmu.style.fontSize = `${options.size}px`;
// 随机垂直位置
const top = Math.random() * (this.container.offsetHeight - 30);
danmu.style.top = `${top}px`;
// 初始位置在容器右侧
danmu.style.left = `${this.container.offsetWidth}px`;
this.container.appendChild(danmu);
// 动画移动
const speed = options.speed || 5;
const duration = (this.container.offsetWidth + danmu.offsetWidth) / speed;
danmu.style.transition = `left ${duration}ms linear`;
setTimeout(() => {
danmu.style.left = `${-danmu.offsetWidth}px`;
}, 0);
// 动画结束后移除元素
danmu.addEventListener('transitionend', () => {
this.container.removeChild(danmu);
});
this.danmus.push(danmu);
}
}
使用弹幕系统
初始化弹幕系统并发送弹幕:
const danmu = new Danmu('danmu-container');
// 发送普通弹幕
danmu.add('这是一条普通弹幕');
// 发送带样式的弹幕
danmu.add('这是一条红色大号弹幕', {
color: 'red',
size: 28,
speed: 8
});
高级功能扩展
实现弹幕池和碰撞检测:
class AdvancedDanmu extends Danmu {
constructor(container) {
super(container);
this.tracks = [];
this.trackHeight = 30;
}
// 初始化轨道
initTracks() {
const trackCount = Math.floor(this.container.offsetHeight / this.trackHeight);
this.tracks = new Array(trackCount).fill().map(() => []);
}
// 添加弹幕(带轨道分配)
add(text, options = {}) {
const danmu = document.createElement('div');
danmu.className = 'danmu-item';
danmu.textContent = text;
if(options.color) danmu.style.color = options.color;
if(options.size) danmu.style.fontSize = `${options.size}px`;
// 寻找可用轨道
const trackIndex = this.findAvailableTrack();
if(trackIndex === -1) return; // 无可用轨道
const top = trackIndex * this.trackHeight;
danmu.style.top = `${top}px`;
danmu.style.left = `${this.container.offsetWidth}px`;
this.container.appendChild(danmu);
const speed = options.speed || 5;
const duration = (this.container.offsetWidth + danmu.offsetWidth) / speed;
danmu.style.transition = `left ${duration}ms linear`;
setTimeout(() => {
danmu.style.left = `${-danmu.offsetWidth}px`;
}, 0);
// 记录弹幕到轨道
this.tracks[trackIndex].push({
element: danmu,
endTime: Date.now() + duration
});
danmu.addEventListener('transitionend', () => {
this.container.removeChild(danmu);
this.tracks[trackIndex] = this.tracks[trackIndex].filter(d => d.element !== danmu);
});
}
// 查找可用轨道
findAvailableTrack() {
const now = Date.now();
for(let i = 0; i < this.tracks.length; i++) {
if(this.tracks[i].length === 0 ||
this.tracks[i][this.tracks[i].length - 1].endTime < now) {
return i;
}
}
return -1;
}
}
性能优化建议
使用Canvas渲染代替DOM操作可以大幅提升性能,特别是在弹幕数量较多时。requestAnimationFrame实现动画比CSS transition更适合精确控制。






