js实现弹幕
弹幕基础实现
HTML结构需包含一个容器元素用于承载弹幕:
<div id="danmu-container" style="position: relative; width: 800px; height: 400px; overflow: hidden;"></div>
CSS样式定义弹幕外观:
.danmu-item {
position: absolute;
white-space: nowrap;
color: #fff;
text-shadow: 1px 1px 2px #000;
font-size: 20px;
user-select: none;
}
弹幕核心逻辑
初始化弹幕池与参数:
const container = document.getElementById('danmu-container');
const danmuPool = [];
const config = {
speed: 2,
fontSize: 20,
rowHeight: 30,
colors: ['#ff0000', '#00ff00', '#0000ff', '#ffff00']
};
弹幕对象构造函数:
class Danmu {
constructor(text, options = {}) {
this.text = text;
this.color = options.color ||
config.colors[Math.floor(Math.random() * config.colors.length)];
this.speed = options.speed || config.speed;
this.top = options.top ||
Math.floor(Math.random() * (container.offsetHeight / config.rowHeight)) * config.rowHeight;
this.left = container.offsetWidth;
this.width = 0;
this.element = null;
}
}
弹幕运动控制
创建DOM元素并初始化位置:
Danmu.prototype.create = function() {
const element = document.createElement('div');
element.className = 'danmu-item';
element.textContent = this.text;
element.style.color = this.color;
element.style.top = `${this.top}px`;
element.style.left = `${this.left}px`;
container.appendChild(element);
this.element = element;
this.width = element.offsetWidth;
};
实现动画帧更新:
Danmu.prototype.update = function() {
this.left -= this.speed;
this.element.style.left = `${this.left}px`;
if (this.left + this.width < 0) {
this.remove();
return false;
}
return true;
};
弹幕管理系统
弹幕池管理与渲染循环:
function addDanmu(text, options) {
const danmu = new Danmu(text, options);
danmu.create();
danmuPool.push(danmu);
}
function animate() {
for (let i = danmuPool.length - 1; i >= 0; i--) {
if (!danmuPool[i].update()) {
danmuPool.splice(i, 1);
}
}
requestAnimationFrame(animate);
}
// 启动动画循环
animate();
功能扩展实现
弹幕发送接口:
function sendDanmu() {
const input = document.getElementById('danmu-input');
if (input.value.trim()) {
addDanmu(input.value.trim());
input.value = '';
}
}
碰撞检测优化(可选):
function getAvailableRow() {
const rows = Math.floor(container.offsetHeight / config.rowHeight);
const occupied = new Array(rows).fill(false);
danmuPool.forEach(danmu => {
const row = Math.floor(danmu.top / config.rowHeight);
if (row >= 0 && row < rows) {
occupied[row] = true;
}
});
for (let i = 0; i < occupied.length; i++) {
if (!occupied[i]) return i * config.rowHeight;
}
return null;
}
性能优化建议
使用Canvas替代DOM:
const canvas = document.getElementById('danmu-canvas');
const ctx = canvas.getContext('2d');
function drawDanmu() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
danmuPool.forEach(danmu => {
ctx.fillStyle = danmu.color;
ctx.font = `${config.fontSize}px sans-serif`;
ctx.fillText(danmu.text, danmu.x, danmu.y);
danmu.x -= danmu.speed;
});
}
节流控制弹幕数量:

let lastTime = 0;
function throttleAddDanmu(text, delay = 300) {
const now = Date.now();
if (now - lastTime >= delay) {
addDanmu(text);
lastTime = now;
}
}






