fix(agent): 切回看过的会话直接铺出历史,长内容不再从顶滚到底
- 事件流按会话缓存最近 30 条会话的已读事件,切回时直接用缓存渲染,再从最后一个 seq 之后补读 - 消息区跟随:一次多出一屏以上直接跳到底,流式小段增长才平滑跟随 (原来只有第一次 ResizeObserver 回调算首屏,事件补读回来时整段平滑滚动) Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Cxwgnn2pbzQ7rXv3rq7fei
This commit is contained in:
1 parent
9f499ac7c2
commit
93a5341688
3 files changed
+78
-10
No files matched your search
@@ -33,6 +33,14 @@ export interface MessageScrollerProps extends Omit<ComponentPropsWithRef<"div">,
|
||||
jumpLabel?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 跟随内容增长时的滚动方式:流式输出的小段增长平滑跟随;一次多出一屏以上(打开 / 切回会话时历史铺开、
|
||||
* 补读回一大段)直接跳到底,不播一段从上滚到底的动画;减少动态效果时一律直接跳。
|
||||
*/
|
||||
export function followBehavior(o: { gap: number; viewport: number; reduce: boolean }): ScrollBehavior {
|
||||
return o.reduce || o.gap > o.viewport ? "auto" : "smooth";
|
||||
}
|
||||
|
||||
function layoutMs(el: Element | null): number {
|
||||
if (!el) return 0;
|
||||
const v = getComputedStyle(el).getPropertyValue("--duration-layout").trim();
|
||||
@@ -113,12 +121,12 @@ export function MessageScroller({
|
||||
useEffect(() => {
|
||||
const content = contentRef.current;
|
||||
if (!content || typeof ResizeObserver === "undefined") return;
|
||||
// 首次铺满内容(回放历史)直接跳到底,之后的增长才平滑跟随
|
||||
let first = true;
|
||||
// 首次铺满内容、一次多出一屏以上直接跳到底,流式的小段增长才平滑跟随
|
||||
const ro = new ResizeObserver(() => {
|
||||
if (!followOutput || !followingRef.current) return;
|
||||
scrollToEnd(reduce || first ? "auto" : "smooth");
|
||||
first = false;
|
||||
const vp = viewportRef.current;
|
||||
if (!vp || !followOutput || !followingRef.current) return;
|
||||
const gap = vp.scrollHeight - vp.scrollTop - vp.clientHeight;
|
||||
scrollToEnd(followBehavior({ gap, viewport: vp.clientHeight, reduce }));
|
||||
});
|
||||
ro.observe(content);
|
||||
return () => ro.disconnect();
|
||||
|
||||
Reference in new issue
Block a user