From ff755afd9991f401fc873ce53cf2ba1ff3fadd46 Mon Sep 17 00:00:00 2001 From: Megghy Date: Mon, 14 Apr 2025 17:05:13 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E5=BC=B9=E5=B9=95?= =?UTF-8?q?=E7=AA=97=E5=8F=A3=E7=AE=A1=E7=90=86=E5=8A=9F=E8=83=BD=EF=BC=9B?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=BC=B9=E5=B9=95=E5=AE=A2=E6=88=B7=E7=AB=AF?= =?UTF-8?q?=E8=BF=9E=E6=8E=A5=E9=80=BB=E8=BE=91=EF=BC=9B=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E6=BB=9A=E5=8A=A8=E5=92=8C=E8=AE=BE=E7=BD=AE?= =?UTF-8?q?=E6=9B=B4=E6=96=B0;=20=E4=BF=AE=E5=A4=8D=E6=B5=8F=E8=A7=88?= =?UTF-8?q?=E9=A1=B5=E9=A1=B5=E9=9D=A2=E5=88=87=E6=8D=A2=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/client/ClientDanmakuWindow.vue | 76 ++++++++- src/client/ClientTest.vue | 6 + src/client/DanmakuWindowManager.vue | 60 ++----- src/client/store/useDanmakuWindow.ts | 159 +++++++++++-------- src/data/DanmakuClients/BaseDanmakuClient.ts | 2 +- src/data/DanmakuClients/DirectClient.ts | 4 +- src/router/client.ts | 7 + src/router/singlePage.ts | 5 +- src/store/useDanmakuClient.ts | 8 +- src/store/useWebFetcher.ts | 6 +- src/views/ViewerLayout.vue | 1 - 11 files changed, 195 insertions(+), 139 deletions(-) diff --git a/src/client/ClientDanmakuWindow.vue b/src/client/ClientDanmakuWindow.vue index a014e14..829aa81 100644 --- a/src/client/ClientDanmakuWindow.vue +++ b/src/client/ClientDanmakuWindow.vue @@ -3,7 +3,8 @@ import { useDanmakuClient } from '@/store/useDanmakuClient'; import { DANMAKU_WINDOW_BROADCAST_CHANNEL, DanmakuWindowBCData, DanmakuWindowSettings } from './store/useDanmakuWindow'; import { NSpin, NEmpty, NIcon } from 'naive-ui'; import { EventDataTypes, EventModel } from '@/api/api-models'; -import { computed, onMounted, onUnmounted, ref, watch } from 'vue'; +// Import nextTick +import { computed, onMounted, onUnmounted, ref, watch, nextTick } from 'vue'; import { TransitionGroup } from 'vue'; import { Money24Regular, VehicleShip24Filled } from '@vicons/fluent'; @@ -11,6 +12,8 @@ let bc: BroadcastChannel | undefined = undefined; const setting = ref(); const danmakuList = ref([]); const maxItems = computed(() => setting.value?.maxDanmakuCount || 50); +// Ref for the scroll container +const scrollContainerRef = ref(null); const isConnected = computed(() => { return setting.value !== undefined; @@ -49,8 +52,8 @@ function formatUsername(item: EventModel): string { function addDanmaku(data: EventModel) { if (!setting.value) return; - // 检查是否是需要过滤的消息类型 - const typeMap: Record = { + // Map EventDataTypes enum values to the string values used in filterTypes + const typeToStringMap: { [key in EventDataTypes]?: string } = { [EventDataTypes.Message]: "Message", [EventDataTypes.Gift]: "Gift", [EventDataTypes.SC]: "SC", @@ -58,12 +61,30 @@ function addDanmaku(data: EventModel) { [EventDataTypes.Enter]: "Enter" }; - const typeStr = typeMap[data.type]; + const typeStr = typeToStringMap[data.type]; + + // Check if the type should be filtered out if (!typeStr || !setting.value.filterTypes.includes(typeStr)) { - return; + return; // Don't add if filtered } - // 维护最大消息数量 + // --- Auto Scroll Logic --- + const el = scrollContainerRef.value; + let shouldScroll = false; + if (el) { + const threshold = 5; // Pixels threshold to consider "at the end" + if (setting.value?.reverseOrder) { + // Check if scrolled to the top before adding + shouldScroll = el.scrollTop <= threshold; + } else { + // Check if scrolled to the bottom before adding + shouldScroll = el.scrollHeight - el.scrollTop - el.clientHeight <= threshold; + } + } + // --- End Auto Scroll Logic --- + + + // Maintain max message count if (setting.value.reverseOrder) { danmakuList.value.unshift(data); if (danmakuList.value.length > maxItems.value) { @@ -75,18 +96,47 @@ function addDanmaku(data: EventModel) { danmakuList.value.shift(); } } + + // --- Auto Scroll Execution --- + if (shouldScroll && el) { + nextTick(() => { + if (setting.value?.reverseOrder) { + el.scrollTop = 0; // Scroll to top + } else { + el.scrollTop = el.scrollHeight; // Scroll to bottom + } + }); + } + // --- End Auto Scroll Execution --- } onMounted(() => { bc = new BroadcastChannel(DANMAKU_WINDOW_BROADCAST_CHANNEL); + console.log(`[DanmakuWindow] BroadcastChannel 已创建: ${DANMAKU_WINDOW_BROADCAST_CHANNEL}`); + bc.postMessage({ + type: 'window-ready', + }) bc.onmessage = (event) => { const data = event.data as DanmakuWindowBCData; switch (data.type) { case 'danmaku': - addDanmaku(data.data); + addDanmaku(data.data); // addDanmaku now handles scrolling + // console.log('[DanmakuWindow] 收到弹幕:', data.data); // Keep console logs minimal if not debugging break; case 'update-setting': setting.value = data.data; + console.log('[DanmakuWindow] 设置已更新:', data.data); + // Adjust scroll on setting change if needed (e.g., reverseOrder changes) + nextTick(() => { + const el = scrollContainerRef.value; + if (el) { + if (setting.value?.reverseOrder) { + el.scrollTop = 0; + } else { + el.scrollTop = el.scrollHeight; + } + } + }); break; } }; @@ -143,6 +193,7 @@ function formatMessage(item: EventModel): string { }" > 测试通知 + + 弹幕机 + ( - key: K, - value: typeof danmakuWindow.danmakuWindowSetting[K] -) { - danmakuWindow.updateSetting(key, value); -}