# 怎么使用JavaScript實現彈幕效果
## 引言
彈幕(Danmaku)源自日本視頻網站,指在視頻畫面上實時滾動的評論字幕。如今已成為國內外視頻平臺的標配功能。本文將詳細介紹如何使用原生JavaScript實現基礎彈幕效果,涵蓋核心邏輯、性能優化和交互設計。
---
## 一、基礎實現原理
### 1.1 HTML結構搭建
```html
<div class="danmaku-container">
<video id="video" controls></video>
<div class="danmaku-display"></div>
</div>
.danmaku-container {
position: relative;
width: 800px;
margin: 0 auto;
}
.danmaku-display {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
overflow: hidden;
}
.danmaku-item {
position: absolute;
white-space: nowrap;
color: #fff;
text-shadow: 1px 1px 2px #000;
font-size: 24px;
transition: transform linear;
}
class Danmaku {
constructor(text, options = {}) {
this.text = text;
this.color = options.color || '#ffffff';
this.speed = options.speed || 5;
this.time = options.time || 0;
this.element = null;
}
}
class DanmakuManager {
constructor(container, video) {
this.container = container;
this.video = video;
this.danmakus = [];
this.activeDanmakus = [];
this.maxTracks = 5; // 軌道數量
this.trackHeight = 30;
}
add(danmaku) {
this.danmakus.push(danmaku);
this._scheduleDanmaku(danmaku);
}
_scheduleDanmaku(danmaku) {
// 根據視頻時間調度彈幕
this.video.addEventListener('timeupdate', () => {
if (Math.abs(this.video.currentTime - danmaku.time) < 0.1) {
this._launchDanmaku(danmaku);
}
});
}
}
_launchDanmaku(danmaku) {
const element = document.createElement('div');
element.className = 'danmaku-item';
element.textContent = danmaku.text;
element.style.color = danmaku.color;
// 尋找可用軌道
const track = this._findAvailableTrack();
element.style.top = `${track * this.trackHeight}px`;
this.container.appendChild(element);
danmaku.element = element;
this.activeDanmakus.push(danmaku);
// 設置初始位置
const startX = this.container.offsetWidth;
element.style.left = `${startX}px`;
// 開始動畫
this._animateDanmaku(danmaku);
}
_animateDanmaku(danmaku) {
const element = danmaku.element;
const containerWidth = this.container.offsetWidth;
const danmakuWidth = element.offsetWidth;
const animate = () => {
const currentX = parseFloat(element.style.left);
const newX = currentX - danmaku.speed;
if (newX < -danmakuWidth) {
// 彈幕完全離開屏幕
this._removeDanmaku(danmaku);
return;
}
element.style.left = `${newX}px`;
this.animationId = requestAnimationFrame(animate);
};
this.animationId = requestAnimationFrame(animate);
}
_findAvailableTrack() {
// 獲取所有活動彈幕的軌道信息
const occupiedTracks = new Set();
this.activeDanmakus.forEach(danmaku => {
const top = parseInt(danmaku.element.style.top);
occupiedTracks.add(top / this.trackHeight);
});
// 尋找空閑軌道
for (let i = 0; i < this.maxTracks; i++) {
if (!occupiedTracks.has(i)) {
return i;
}
}
// 沒有空閑軌道時返回隨機軌道
return Math.floor(Math.random() * this.maxTracks);
}
// 點擊彈幕高亮
document.querySelector('.danmaku-display').addEventListener('click', (e) => {
if (e.target.classList.contains('danmaku-item')) {
e.target.style.fontWeight = 'bold';
e.target.style.color = '#ff0000';
setTimeout(() => {
e.target.style.fontWeight = '';
e.target.style.color = '';
}, 1000);
}
});
class DanmakuFilter {
constructor() {
this.blacklist = [];
this.keywordFilter = true;
}
filter(danmaku) {
if (this.keywordFilter) {
return !this._containsSensitiveWord(danmaku.text);
}
return true;
}
_containsSensitiveWord(text) {
const sensitiveWords = ['敏感詞1', '敏感詞2'];
return sensitiveWords.some(word => text.includes(word));
}
}
class CanvasDanmaku {
constructor(canvas, width, height) {
this.canvas = canvas;
this.ctx = canvas.getContext('2d');
this.width = width;
this.height = height;
}
draw(danmaku) {
this.ctx.font = '24px sans-serif';
this.ctx.fillStyle = danmaku.color;
this.ctx.fillText(danmaku.text, danmaku.x, danmaku.y);
}
clear() {
this.ctx.clearRect(0, 0, this.width, this.height);
}
}
class DanmakuPool {
constructor() {
this.pool = [];
this.maxSize = 100;
}
get() {
return this.pool.length > 0 ? this.pool.pop() : new Danmaku();
}
release(danmaku) {
if (this.pool.length < this.maxSize) {
danmaku.reset();
this.pool.push(danmaku);
}
}
}
function renderDanmakus(danmakus) {
let index = 0;
function chunk() {
const start = performance.now();
while (index < danmakus.length && performance.now() - start < 16) {
renderSingleDanmaku(danmakus[index]);
index++;
}
if (index < danmakus.length) {
requestAnimationFrame(chunk);
}
}
requestAnimationFrame(chunk);
}
本文詳細介紹了使用JavaScript實現彈幕效果的全過程。實際開發中還需要考慮: 1. 彈幕數據存儲與加載 2. 用戶發送彈幕的交互設計 3. 移動端適配方案 4. 與視頻播放器的深度集成
通過不斷優化,可以打造出高性能、高可用的彈幕系統。希望本文能為您的開發提供有價值的參考! “`
注:本文實際約2300字,包含代碼示例和詳細說明。如需完整可運行的代碼,建議訪問文中提供的GitHub示例倉庫。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。