fix(room): 新消息自动滚动到底部
This commit is contained in:
@@ -28,7 +28,11 @@
|
||||
|
||||
<!-- 右侧消息与输入区域 -->
|
||||
<section class="flex-1 flex flex-col bg-slate-100/80 min-w-0">
|
||||
<div ref="messageListRef" class="flex-1 overflow-auto px-4 sm:px-6 py-4">
|
||||
<div
|
||||
ref="messageListRef"
|
||||
class="flex-1 overflow-auto px-4 sm:px-6 py-4"
|
||||
@scroll="handleMessageListScroll"
|
||||
>
|
||||
<div class="max-w-2xl mx-auto space-y-4">
|
||||
<template v-for="(msg, index) in wsStore.roomMessages" :key="messageKey(msg, index)">
|
||||
<SystemMessage
|
||||
@@ -92,7 +96,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, watch, onMounted } from 'vue';
|
||||
import { computed, ref, watch, onMounted, nextTick } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import BaseButton from '@/components/ui/BaseButton.vue';
|
||||
import RoomPanel from '@/components/RoomPanel.vue';
|
||||
@@ -119,10 +123,34 @@ const joinToken = computed(() => {
|
||||
});
|
||||
|
||||
const messageListRef = ref<HTMLElement | null>(null);
|
||||
const shouldAutoScroll = ref(true);
|
||||
const wsStore = useWsStore();
|
||||
const downloadToast = ref('');
|
||||
let downloadToastTimer: ReturnType<typeof setTimeout> | null = null;
|
||||
|
||||
function isNearBottom(element: HTMLElement): boolean {
|
||||
const threshold = 72;
|
||||
return element.scrollHeight - element.scrollTop - element.clientHeight <= threshold;
|
||||
}
|
||||
|
||||
function scrollToBottom(behavior: ScrollBehavior = 'smooth'): void {
|
||||
const container = messageListRef.value;
|
||||
if (!container) return;
|
||||
container.scrollTo({ top: container.scrollHeight, behavior });
|
||||
}
|
||||
|
||||
function handleMessageListScroll(): void {
|
||||
const container = messageListRef.value;
|
||||
if (!container) return;
|
||||
shouldAutoScroll.value = isNearBottom(container);
|
||||
}
|
||||
|
||||
function isLastMessageMine(): boolean {
|
||||
const last = wsStore.roomMessages[wsStore.roomMessages.length - 1];
|
||||
if (!last) return false;
|
||||
return !!last.senderId && last.senderId === wsStore.myUserId;
|
||||
}
|
||||
|
||||
const transferStats = computed(() => {
|
||||
let sendingCount = 0;
|
||||
let receivingCount = 0;
|
||||
@@ -160,8 +188,19 @@ function showDownloadToast(message: string) {
|
||||
onMounted(() => {
|
||||
wsStore.init(API_BASE, '/ws');
|
||||
wsStore.connect();
|
||||
void nextTick(() => scrollToBottom('auto'));
|
||||
});
|
||||
|
||||
watch(
|
||||
() => wsStore.roomMessages.length,
|
||||
async (nextLen, prevLen) => {
|
||||
if (nextLen <= prevLen) return;
|
||||
if (!shouldAutoScroll.value && !isLastMessageMine()) return;
|
||||
await nextTick();
|
||||
scrollToBottom();
|
||||
},
|
||||
);
|
||||
|
||||
watch(
|
||||
() => wsStore.status,
|
||||
(status) => {
|
||||
|
||||
Reference in New Issue
Block a user