fix(chat): 修复内容大幅增长时滚动锁定不及时的问题
- 调整 vue-stick-to-bottom resize spring 参数,加快动画响应 (damping 0.68→0.5, stiffness 0.11→0.28, mass 1.05→0.75) - 在 scrollListener 中添加高度突变检测,当 scrollHeight 大幅增长 (超过 200px 或 viewport 35%)且用户未脱离锁定时,用 instant 瞬间追底,绕过 spring 动画延迟和去重机制 修复场景:思考块展开、Markdown 表格渲染等造成大幅度垂直距离增加时 滚动锁定失效或锁住不及时的问题
This commit is contained in:
parent
2fcd241d94
commit
8d87068ba7
@ -790,9 +790,9 @@ const {
|
||||
stopScroll
|
||||
} = useStickToBottom({
|
||||
resize: {
|
||||
damping: 0.68,
|
||||
stiffness: 0.11,
|
||||
mass: 1.05
|
||||
damping: 0.5,
|
||||
stiffness: 0.28,
|
||||
mass: 0.75
|
||||
},
|
||||
initial: 'instant'
|
||||
});
|
||||
@ -809,6 +809,7 @@ let lastUserWheelUpTs = 0;
|
||||
let lastProgrammaticHintTs = 0;
|
||||
let lastProgrammaticHintSource = '';
|
||||
let suppressUserIntentUntil = 0;
|
||||
let isHandlingLargeGrowth = false;
|
||||
let scrollListener: ((event: Event) => void) | null = null;
|
||||
let wheelListener: ((event: WheelEvent) => void) | null = null;
|
||||
let traceAttachLogged = false;
|
||||
@ -924,6 +925,32 @@ function attachBounceListener() {
|
||||
const heightDelta = height - lastObservedHeight;
|
||||
lastObservedTop = top;
|
||||
lastObservedHeight = height;
|
||||
|
||||
// 大幅高度增长检测:当 scrollHeight 突增(内容大幅展开/渲染),
|
||||
// 且用户没有主动脱离锁定(escapedFromLock=false)时,
|
||||
// 用 instant 瞬间追底,绕过 spring 动画的延迟。
|
||||
// 这解决了思考块展开、Markdown 表格渲染等场景下滚动跟不上内容增长的问题。
|
||||
const largeGrowthThreshold = Math.max(200, target.clientHeight * 0.35 || 200);
|
||||
if (
|
||||
!isHandlingLargeGrowth &&
|
||||
heightDelta > largeGrowthThreshold &&
|
||||
!escapedFromLock.value
|
||||
) {
|
||||
isHandlingLargeGrowth = true;
|
||||
markProgrammaticHint('ChatArea.largeGrowth');
|
||||
suppressUserIntentUntil = Date.now() + 900;
|
||||
scrollToBottom({ animation: 'instant', preserveScrollPosition: false });
|
||||
bounceTraceLog(
|
||||
'large-growth:instant-scroll',
|
||||
{ heightDelta, threshold: largeGrowthThreshold, ...getScrollMetrics(target) },
|
||||
'large-growth:instant-scroll',
|
||||
120
|
||||
);
|
||||
setTimeout(() => {
|
||||
isHandlingLargeGrowth = false;
|
||||
}, 400);
|
||||
}
|
||||
|
||||
const now = Date.now();
|
||||
const trusted = (event as any).isTrusted === true;
|
||||
const closeToProgrammaticHint = now - lastProgrammaticHintTs <= 140;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user