fix(chat): 运行中逐帧贴底锁,修复块外框与内容移动不同步
This commit is contained in:
parent
a7a40a8a2f
commit
677604b538
@ -1215,6 +1215,52 @@ const { anchorBlockElement, stopAll: stopBlockExpansionAnchors } = useBlockExpan
|
||||
scrollRef,
|
||||
{ stopScroll }
|
||||
);
|
||||
|
||||
// —— 运行中逐帧贴底锁 ——
|
||||
// 背景:stick 库的 resize 追底在 ResizeObserver 回调里再经 rAF 才真正写 scrollTop,
|
||||
// 且它观察的 .messages-flow 自身高度要等 virtua 回写占位高度后才变化,整体滞后内容
|
||||
// 增长 1~2 帧。运行中块高度过渡(思考块自动展开/流式增长/手动展开)的每一帧会先按
|
||||
// 新高度绘制、下一帧才被追底拉回,表现为「块外框先动、内部文字慢一步」的不同步。
|
||||
// 这里在对话运行期间持有 rAF(绘制前强制读取 scrollHeight 并同步吸附底部),让高度
|
||||
// 增长与滚动补偿落在同一帧。用户上滚脱离锁定(escapedFromLock/isAtBottom 变 false)
|
||||
// 时自动停止吸附,滚回底部后自动恢复;非运行期仍由 useBlockExpansionAnchor 处理。
|
||||
let liveStickLockRaf: number | null = null;
|
||||
|
||||
function liveStickLockTick() {
|
||||
liveStickLockRaf = null;
|
||||
if (!props.streamingMessage) return;
|
||||
const el = scrollRef.value;
|
||||
if (el && isAtBottom.value && !escapedFromLock.value) {
|
||||
const maxTop = el.scrollHeight - el.clientHeight;
|
||||
if (maxTop - el.scrollTop > 1) {
|
||||
markProgrammaticHint('ChatArea.liveStickLock');
|
||||
el.scrollTop = maxTop;
|
||||
}
|
||||
}
|
||||
liveStickLockRaf = requestAnimationFrame(liveStickLockTick);
|
||||
}
|
||||
|
||||
function stopLiveStickLock() {
|
||||
if (liveStickLockRaf !== null) {
|
||||
cancelAnimationFrame(liveStickLockRaf);
|
||||
liveStickLockRaf = null;
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.streamingMessage,
|
||||
(streaming) => {
|
||||
if (streaming) {
|
||||
if (liveStickLockRaf === null) {
|
||||
liveStickLockRaf = requestAnimationFrame(liveStickLockTick);
|
||||
}
|
||||
} else {
|
||||
stopLiveStickLock();
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
const thinkingRefs = new Map<string, HTMLElement | null>();
|
||||
let scrollbarResizeObserver: ResizeObserver | null = null;
|
||||
let bounceTraceCount = 0;
|
||||
@ -2082,6 +2128,7 @@ watch(scrollRef, () => {
|
||||
onBeforeUnmount(() => {
|
||||
detachBounceListener();
|
||||
stopBlockExpansionAnchors();
|
||||
stopLiveStickLock();
|
||||
if (scrollbarResizeObserver) {
|
||||
scrollbarResizeObserver.disconnect();
|
||||
scrollbarResizeObserver = null;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user