From dd642782b49b524bc9929b2ef0ec052bc08dbd23 Mon Sep 17 00:00:00 2001
From: Vaica <94612053+zqlit@users.noreply.github.com>
Date: Mon, 26 Jan 2026 23:09:57 +0800
Subject: [PATCH] =?UTF-8?q?fixed=20=E5=BC=B9=E5=B9=95=E4=BF=AE=E5=A4=8D?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
hugo.toml | 1 +
themes/Ying/assets/css/main.css | 167 ++++++++-----
themes/Ying/assets/js/barrage.js | 285 ++++++++++++++++++++++
themes/Ying/assets/js/main.js | 88 +------
themes/Ying/layouts/partials/barrage.html | 4 +
themes/Ying/layouts/partials/footer.html | 3 +-
themes/Ying/layouts/partials/head.html | 2 +-
themes/Ying/layouts/partials/header.html | 2 +
8 files changed, 417 insertions(+), 135 deletions(-)
create mode 100644 themes/Ying/assets/js/barrage.js
create mode 100644 themes/Ying/layouts/partials/barrage.html
diff --git a/hugo.toml b/hugo.toml
index c9e337fc..c88c7116 100644
--- a/hugo.toml
+++ b/hugo.toml
@@ -126,6 +126,7 @@ hasCJKLanguage = true
# 弹幕配置 (Barrage Configuration)
# ----------------------------------------------------------------------------
[params.barrage]
+ enable = true
enableHitokoto = true
hitokotoUrl = "https://v1.hitokoto.cn?c=a&c=b&c=c&c=d&c=i"
diff --git a/themes/Ying/assets/css/main.css b/themes/Ying/assets/css/main.css
index d00eff82..4fea277f 100644
--- a/themes/Ying/assets/css/main.css
+++ b/themes/Ying/assets/css/main.css
@@ -2192,69 +2192,126 @@ input[type=submit] {
}
/* 弹幕css */
-.barrage {
- display: -webkit-box;
- display: -webkit-flex;
- display: -moz-box;
- display: -ms-flexbox;
- display: flex;
- -webkit-box-orient: horizontal;
- -webkit-box-direction: normal;
- -webkit-flex-direction: row;
- -moz-box-orient: horizontal;
- -moz-box-direction: normal;
- -ms-flex-direction: row;
- flex-direction: row;
- cursor: pointer;
- -webkit-flex-wrap: nowrap;
- -ms-flex-wrap: nowrap;
- flex-wrap: nowrap;
- -webkit-box-align: center;
- -webkit-align-items: center;
- -moz-box-align: center;
- -ms-flex-align: center;
- align-items: center;
- word-break: keep-all;
- white-space: nowrap;
- -webkit-border-radius: 20px;
- border-radius: 20px;
- padding: 0 20px;
- padding-left: 15px;
- opacity: 0.8;
- will-change: transform;
+.barrager {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ pointer-events: none; /* 容器不阻挡点击 */
+ z-index: 1; /* 在 main (z-index: 10) 背后,但在 body 背景之上 */
+ overflow: hidden;
+}
+
+/* 弹幕条目 (左到右) */
+.barrage-item {
position: absolute;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
+ display: inline-flex;
+ align-items: flex-start; /* 顶部对齐 */
+ white-space: nowrap;
+ will-change: transform;
+ pointer-events: auto; /* 弹幕本身可点击 */
user-select: none;
- pointer-events: auto;
- text-shadow: 0ch;
- z-index: 11;
+ transform: translateX(-100%); /* 初始在左侧外 */
+ z-index: 10;
+ /* 初始透明度,配合动画实现淡入淡出 */
+ opacity: 0.9;
+ /* 缩小整体尺寸 */
+ transform-origin: left top;
}
-.barrage .header-avatar {
- -webkit-border-radius: 50%;
+/* 头像样式 */
+.barrage-avatar {
+ width: 28px; /* 缩小头像 */
+ height: 28px;
border-radius: 50%;
- position: relative;
- right: 7px;
- display: flex;
- align-items: center;
- justify-content: center;
- width: 26px !important;
- height: 26px !important;
- min-width: 26px !important;
-}
-
-.barrage .header-avatar img {
- width: 26px !important;
- height: 26px !important;
+ margin-right: 8px;
object-fit: cover;
- border-radius: 50%;
+ border: 1px solid rgba(0,0,0,0.05);
+ box-shadow: 0 1px 2px rgba(0,0,0,0.1);
+ flex-shrink: 0;
+ background: #fff;
}
-.pause {
- -webkit-animation-play-state: paused;
- animation-play-state: paused;
+/* 聊天气泡样式 (仿QQ/微信风格) */
+.barrage-bubble {
+ background: #ffffff; /* QQ/微信 白底 */
+ color: #1f1f1f; /* 深黑文字 */
+ padding: 6px 10px; /* 缩小内边距 */
+ border-radius: 6px; /* 稍微减小圆角 */
+ font-size: 13px; /* 缩小字体 */
+ line-height: 1.4;
+ position: relative;
+ box-shadow: 0 1px 5px rgba(0,0,0,0.08);
+ max-width: 260px; /* 减小最大宽度 */
+ white-space: normal;
+ word-break: break-all;
+}
+
+/* 气泡小尾巴 */
+.barrage-bubble::before {
+ content: '';
+ position: absolute;
+ top: 10px; /* 调整位置 */
+ left: -5px; /* 调整大小 */
+ width: 0;
+ height: 0;
+ border-top: 5px solid transparent;
+ border-bottom: 5px solid transparent;
+ border-right: 5px solid #ffffff;
+}
+
+/* 昼夜切换适配 */
+[data-theme="dark"] .barrage-avatar {
+ border-color: #444;
+ background: #222;
+}
+
+[data-theme="dark"] .barrage-bubble {
+ background: #262626; /* 深色模式深灰底 */
+ color: #e5e5e5;
+ border: 1px solid rgba(255,255,255,0.05);
+ box-shadow: none;
+}
+
+[data-theme="dark"] .barrage-bubble::before {
+ border-right-color: #262626;
+}
+
+/* 悬停效果 */
+.barrage-item:hover .barrage-bubble {
+ background: #f0f0f0; /* 悬停微暗 */
+ z-index: 100;
+}
+
+.barrage-item:hover .barrage-bubble::before {
+ border-right-color: #f0f0f0;
+}
+
+[data-theme="dark"] .barrage-item:hover .barrage-bubble {
+ background: #333;
+}
+
+[data-theme="dark"] .barrage-item:hover .barrage-bubble::before {
+ border-right-color: #333;
+}
+
+/* 左到右动画的关键帧 */
+@keyframes barrage-slide-right {
+ 0% {
+ transform: translateX(-100%); /* 左侧屏幕外 */
+ opacity: 0;
+ }
+ 5% {
+ opacity: 1; /* 快速淡入 */
+ }
+ 95% {
+ opacity: 1;
+ }
+ 100% {
+ transform: translateX(100vw); /* 右侧屏幕外 */
+ opacity: 0; /* 淡出 */
+ }
}
/* artalk样式重写css */
diff --git a/themes/Ying/assets/js/barrage.js b/themes/Ying/assets/js/barrage.js
new file mode 100644
index 00000000..609786c6
--- /dev/null
+++ b/themes/Ying/assets/js/barrage.js
@@ -0,0 +1,285 @@
+// 弹幕功能封装
+(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 += `