fixed 弹幕卡顿

This commit is contained in:
Vaica committed 2026-01-29 21:19:49 +08:00
1 parent 7aed8a4597
commit cc5a5130e5
2 files changed
+68 -33

No files matched your search

+7
View File
@@ -2224,6 +2224,10 @@ input[type=submit] {
pointer-events: none; /* 容器不阻挡点击 */
z-index: 1; /* 在 main (z-index: 10) 背后,但在 body 背景之上 */
overflow: hidden;
/* 性能优化:CSS 隔离 */
contain: layout style paint;
/* 某些浏览器可能支持 content-visibility */
content-visibility: auto;
}
/* 弹幕条目 (左到右) */
@@ -2241,6 +2245,9 @@ input[type=submit] {
opacity: 0.9;
/* 缩小整体尺寸 */
transform-origin: left top;
/* 硬件加速 */
backface-visibility: hidden;
-webkit-font-smoothing: antialiased;
}
/* 头像样式 */
+61 -33
View File
@@ -135,6 +135,54 @@
// 追踪当前屏幕上显示的弹幕 ID
this.activeIds = new Set();
// 最大同屏数量限制,防止卡顿
this.maxActiveItems = 30;
// 绑定事件委托
this.initEventDelegation();
}
initEventDelegation() {
// 鼠标进入容器暂停
this.container.addEventListener('mouseover', (e) => {
const item = e.target.closest('.barrage-item');
if (item) {
item.style.animationPlayState = 'paused';
item.style.zIndex = '9999';
}
});
// 鼠标离开恢复
this.container.addEventListener('mouseout', (e) => {
const item = e.target.closest('.barrage-item');
if (item) {
item.style.animationPlayState = 'running';
item.style.zIndex = '';
}
});
// 点击事件
this.container.addEventListener('click', (e) => {
const item = e.target.closest('.barrage-item');
if (item) {
const url = item.dataset.url;
if (url && url !== '#') {
e.stopPropagation();
e.preventDefault();
const targetId = url.split('#')[1];
const targetEl = document.getElementById(targetId);
if (targetEl) {
targetEl.scrollIntoView({ behavior: 'smooth', block: 'center' });
targetEl.classList.add('atk-flash');
setTimeout(() => targetEl.classList.remove('atk-flash'), 2000);
} else {
window.location.href = url;
}
}
}
});
}
start(data = []) {
@@ -180,6 +228,7 @@
this.isDestroyed = true;
this.stop();
this.clearDOM();
// 移除事件监听需要保存引用,这里因为容器可能被销毁,且是单例,暂不处理复杂的解绑
}
loop() {
@@ -187,15 +236,15 @@
// 容器检测
if (!document.body.contains(this.container)) {
// 尝试重新获取容器 (可能被 PJAX 替换但 ID 没变?)
// 这里简单处理:如果失效则停止
// console.warn('[Barrage] 容器失效,停止');
this.destroy();
return;
}
if (!this.isPaused && this.data.length > 0) {
this.tryShoot();
// 只有当前屏幕数量未满时才发射
if (this.activeIds.size < this.maxActiveItems) {
this.tryShoot();
}
}
// 随机间隔 2s - 4s
@@ -226,33 +275,20 @@
const item = document.createElement('div');
item.className = 'barrage-item';
// 存储 URL 到 dataset 以供事件委托使用
if (url && url !== '#') {
item.dataset.url = url;
item.style.cursor = 'pointer';
}
let html = '';
// 优化:只有当有头像时才渲染 img 标签
if (avatar) {
html += `<img src="${avatar}" class="barrage-avatar" draggable="false">`;
html += `<img src="${avatar}" class="barrage-avatar" draggable="false" loading="lazy">`;
}
html += `<div class="barrage-bubble"><span class="barrage-text">${text}</span></div>`;
item.innerHTML = html;
if (url && url !== '#') {
item.style.cursor = 'pointer';
item.addEventListener('click', (e) => {
e.stopPropagation();
e.preventDefault();
const targetId = url.split('#')[1];
const targetEl = document.getElementById(targetId);
if (targetEl) {
targetEl.scrollIntoView({ behavior: 'smooth', block: 'center' });
targetEl.classList.add('atk-flash');
setTimeout(() => targetEl.classList.remove('atk-flash'), 2000);
} else {
window.location.href = url;
}
});
}
// 样式与动画
const tracks = 10;
const trackIndex = Math.floor(Math.random() * tracks);
@@ -263,15 +299,7 @@
const duration = 18 + Math.random() * 7;
item.style.animation = `barrage-slide-right ${duration}s linear forwards`;
item.addEventListener('mouseenter', () => {
item.style.animationPlayState = 'paused';
item.style.zIndex = '9999';
});
item.addEventListener('mouseleave', () => {
item.style.animationPlayState = 'running';
item.style.zIndex = '';
});
// 仅绑定必要的生命周期事件
item.addEventListener('animationend', () => {
item.remove();
this.activeIds.delete(id);