// 弹幕功能封装
(function() {
// 异步初始化 Artalk 并获取评论数据
function initArtalkAndGetComments() {
return new Promise((resolve, reject) => {
// 检查 Artalk 是否存在,增加轮询等待机制
if (typeof Artalk === 'undefined') {
let attempts = 0;
const maxAttempts = 50; // 最多等待 5 秒
const interval = setInterval(() => {
attempts++;
if (typeof Artalk !== 'undefined') {
clearInterval(interval);
Artalk.use((ctx) => {
ctx.on('list-loaded', () => {
console.log('评论列表加载完毕');
const commentsData = ctx.getComments();
if (commentsData) {
resolve(commentsData);
} else {
reject('获取评论数据失败');
}
});
});
} else if (attempts >= maxAttempts) {
clearInterval(interval);
console.warn('Artalk 加载超时');
reject('Artalk 未定义 (加载超时)');
}
}, 100);
return;
}
Artalk.use((ctx) => {
ctx.on('list-loaded', () => {
console.log('评论列表加载完毕');
const commentsData = ctx.getComments();
if (commentsData) {
resolve(commentsData);
} else {
reject('获取评论数据失败');
}
});
});
});
}
// 弹幕类 (基于 min-barrage 逻辑)
class BarrageEngine {
constructor(options = {}) {
this.container = typeof options.container === 'string'
? document.querySelector(options.container)
: options.container;
if (!this.container) {
console.warn('[Barrage] 错误: 找不到弹幕容器');
return;
}
this.data = [];
this.index = 0;
this.timer = null;
this.isPaused = false;
}
// 开始发送
start(data = []) {
console.log(`[Barrage] 启动弹幕,共 ${data.length} 条`);
this.data = data;
if (this.data.length === 0) return;
this.clear();
this.loop();
}
// 清空
clear() {
if (this.timer) clearTimeout(this.timer);
// 清除容器内所有弹幕元素
if (this.container) {
const items = this.container.querySelectorAll('.barrage-item');
items.forEach(item => item.remove());
}
this.index = 0;
}
// 循环发射
loop() {
// 如果容器不在文档中(PJAX切换后),尝试重新获取容器
// (注意:this.container 是 DOM 引用,如果页面重绘,旧引用可能失效)
if (!document.body.contains(this.container)) {
console.warn('[Barrage] 容器失效,尝试重新获取...');
const newContainer = document.querySelector('.barrager');
if (newContainer) {
this.container = newContainer;
console.log('[Barrage] 容器重新获取成功,继续播放');
} else {
console.warn('[Barrage] 容器彻底丢失,停止播放');
return; // 真的没了再停止
}
}
// 发射逻辑
if (!this.isPaused) {
const itemData = this.data[this.index];
this.shoot(itemData);
this.index = (this.index + 1) % this.data.length;
}
// 随机间隔 1s - 3s
const interval = 1000 + Math.random() * 2000;
this.timer = setTimeout(() => this.loop(), interval);
}
// 发射单条
shoot(itemData) {
const { text, avatar, url, id } = itemData;
const item = document.createElement('div');
item.className = 'barrage-item';
// 构造内部 HTML 结构:头像 + 气泡
let html = '';
// 1. 头像
if (avatar) {
html += ``;
}
// 2. 气泡 (包裹文本)
html += `