This commit is contained in:
Cledwyn Lew
2026-01-29 10:24:21 +08:00
parent bec0684e70
commit 9179e021e1
5 changed files with 39 additions and 496 deletions

View File

@@ -40,7 +40,10 @@ export const MessageEditArea = ({
return (
<div
className={mjChatCls(['msg-edit-textarea-wrapper'], 'w-full')}
className={mjChatCls(
['msg-edit-textarea-wrapper'],
'w-full max-h-[70vh] overflow-auto rounded-xl border-2 border-white/30',
)}
style={{
height: wrapHeight,
}}

View File

@@ -112,7 +112,7 @@ export const MessageItem = React.memo((props: MessageItemProps) => {
await onEdit(id, editedMessage);
setIsEditing(false);
setTimeout(() => scrollMessageIntoView(), 50);
setTimeout(() => scrollMessageIntoView('end', 'smooth'), 100);
}
};
@@ -212,7 +212,7 @@ export const MessageItem = React.memo((props: MessageItemProps) => {
: originalMessage.swipes[activeSwipeId],
);
// 滚动到消息位置
setTimeout(() => scrollMessageIntoView('nearest', 'smooth'), 10);
setTimeout(() => scrollMessageIntoView('end', 'smooth'), 100);
}}
/>
<MessageActions

View File

@@ -1,7 +1,7 @@
import type { Message as MessageType } from '@mujian/js-sdk/react';
import { Thread, type VListHandle } from '@mujian/js-sdk/react';
import { throttle } from 'lodash-es';
import React, { useEffect, useMemo, useRef, useState } from 'react';
import { useThrottleFn } from 'ahooks';
import React, { useLayoutEffect, useMemo, useRef, useState } from 'react';
import { useGlobalStore } from '@/store/global';
import { MessageItem } from './MessageItem/';
@@ -29,13 +29,14 @@ export const MessageList = React.memo(
onSwipe,
onNeedMore,
}: MsgProps) => {
const prevLastMesRef = useRef<string | undefined>(undefined);
const prevDataLength = useRef(0);
const prevLastMsgId = useRef('');
const { activePersona, projectInfo } = useGlobalStore();
const vListRef = useRef<VListHandle>(null);
const [visibleRange, setVisibleRange] = useState<[number, number]>([0, 0]);
const [shifting, setShifting] = useState(false);
useEffect(() => {
useLayoutEffect(() => {
const vl = vListRef.current;
if (!vl) {
return;
@@ -44,21 +45,29 @@ export const MessageList = React.memo(
vl.viewportSize + vl.scrollOffset + 16 >= vl.scrollSize;
const lastMessage = data[data.length - 1];
const shouldScroll = [
lastMessage?.id !== prevLastMesRef.current, // 新消息
lastMessage?.isStreaming && isScrolledBottom(), // 正在生成
const shouldScrollToBottom = [
data.length !== prevDataLength.current &&
prevLastMsgId.current !== lastMessage?.id, // 新消息
lastMessage?.isStreaming && isScrolledBottom(),
].some(Boolean);
if (shouldScroll) {
vListRef.current?.scrollTo(
prevLastMesRef.current ? vl.scrollSize : 9999999,
);
if (shouldScrollToBottom) {
vl.scrollTo(prevDataLength.current ? vl.scrollSize : 9999999);
}
prevLastMesRef.current = lastMessage?.id;
// 因为最后一条消息的ID会在生成完毕后改变会导致最后一条消息被滚动出去。这里进行滚动位置恢复
const shouldRecoverScroll =
prevDataLength.current === data.length &&
prevLastMsgId.current !== lastMessage?.id;
if (shouldRecoverScroll) {
vl.scrollTo(vl.scrollOffset);
}
prevDataLength.current = data.length;
prevLastMsgId.current = lastMessage?.id;
}, [data]);
const onScroll = throttle(
const { run: onScroll } = useThrottleFn(
() => {
const vl = vListRef.current;
if (!vl) {
@@ -79,8 +88,8 @@ export const MessageList = React.memo(
});
}
},
300,
{
wait: 300,
leading: false,
},
);