From ad5b67ea3edb3596f2d2b87ed191fdcffee6c58c Mon Sep 17 00:00:00 2001 From: thzxx Date: Sat, 13 Jun 2026 09:24:21 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=B7=A5=E5=85=B7=E9=A1=B5=E7=AD=BE?= =?UTF-8?q?=E6=BB=9A=E5=8A=A8=E5=BD=BB=E5=BA=95=E9=87=8D=E5=86=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 统一 scrollToolsToBottom:scrollTop=scrollHeight + 双重rAF - appendToolCardDOM/updateToolCardDOM/renderToolCalls 全部调用 - 废弃 scrollIntoView(overflow-y:auto 容器中不稳定) - 卡片更新后也跟随滚动(结果内容可能导致高度变化) --- src/renderer/components/workspace-panel.ts | 24 +++++++++++++--------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/renderer/components/workspace-panel.ts b/src/renderer/components/workspace-panel.ts index 11931af..ed86ed5 100644 --- a/src/renderer/components/workspace-panel.ts +++ b/src/renderer/components/workspace-panel.ts @@ -836,11 +836,9 @@ function appendToolCardDOM(tc: ToolCallRecord): void { if (card) { card.dataset.toolName = tc.name; container.appendChild(card); - // 等浏览器完成布局后再滚到底部 - requestAnimationFrame(() => { - container.lastElementChild?.scrollIntoView({ block: 'end' }); - }); } + // 始终滚到底部 + scrollToolsToBottom(container); } /** 增量更新工具卡片 DOM 节点(找到 pending/running 状态的卡片并替换) */ @@ -861,6 +859,8 @@ function updateToolCardDOM(tc: ToolCallRecord): void { if (newCard) { newCard.dataset.toolName = tc.name; runningCard.replaceWith(newCard); + // 卡片内容变化后可能变高(如出现执行结果),跟随滚动 + scrollToolsToBottom(container); } } else { // running 卡片不在 DOM 中(可能是 tab 切换后再切回或其他边缘情况) @@ -869,6 +869,15 @@ function updateToolCardDOM(tc: ToolCallRecord): void { } } +/** 工具页签滚动到底部(双重 rAF 保证布局完成) */ +function scrollToolsToBottom(container: HTMLElement): void { + requestAnimationFrame(() => { + requestAnimationFrame(() => { + container.scrollTop = container.scrollHeight; + }); + }); +} + /** CSS.escape 回退(兼容旧 Electron) */ function escapeAttr(value: string): string { try { return CSS.escape(value); } catch { return value.replace(/["\\]/g, '\\$&'); } @@ -943,12 +952,7 @@ function renderToolCalls(): void { html += renderToolCard(tc); } container.innerHTML = html; - // 全量重建后等两帧让布局稳定,再滚到底部 - requestAnimationFrame(() => { - requestAnimationFrame(() => { - container.lastElementChild?.scrollIntoView({ block: 'end' }); - }); - }); + scrollToolsToBottom(container); } function getToolDisplayName(name: string): string {