fix(chatui): preserve scroll position while loading history

This commit is contained in:
Soulter
2026-09-25 11:14:32 +08:00
parent 67c74b7ed8
commit a26d74bd3c
2 changed files with 20 additions and 2 deletions
+6 -1
View File
@@ -1631,6 +1631,7 @@ async function loadEarlierWithAnchor() {
const container = messagesContainer.value;
const firstMessage = activeMessages.value[0];
const firstId = firstMessage?.id == null ? "" : String(firstMessage.id);
const beforeScrollTop = Math.max(0, container?.scrollTop || 0);
const beforeTop = firstId
? container
?.querySelector<HTMLElement>(
@@ -1648,7 +1649,11 @@ async function loadEarlierWithAnchor() {
`[data-message-id="${CSS.escape(firstId)}"]`,
);
if (row) {
container.scrollTop += row.getBoundingClientRect().top - beforeTop;
const currentScrollTop = Math.max(0, container.scrollTop);
const userScrollDelta = currentScrollTop - beforeScrollTop;
container.scrollTop +=
row.getBoundingClientRect().top - beforeTop + userScrollDelta;
lastMessagesScrollTop = Math.max(0, container.scrollTop);
}
} finally {
suppressAutoScroll.value = false;
+14 -1
View File
@@ -47,11 +47,14 @@ test("failed history loading pauses scroll requests until an explicit retry", as
};
const current = { id: 51, content: { message: [] } };
const records = { session: [current] };
let anchorTop = 100;
const container = {
scrollHeight: 1000,
clientHeight: 400,
scrollTop: 0,
querySelector: () => null,
querySelector: () => ({
getBoundingClientRect: () => ({ top: anchorTop }),
}),
};
const requests = [];
const context = vm.createContext({
@@ -61,6 +64,7 @@ test("failed history loading pauses scroll requests until an explicit retry", as
messagesContainer: { value: container },
suppressAutoScroll: { value: false },
LOAD_EARLIER_SCROLL_THRESHOLD: 120,
lastMessagesScrollTop: 0,
CSS: { escape: (value) => value },
nextTick: async () => {},
paginationBySession: { session: state },
@@ -96,6 +100,7 @@ test("failed history loading pauses scroll requests until an explicit retry", as
"scroll events must not retry a failed page",
);
container.scrollTop = 80;
const retry = context.retryCurrentSessionLoad();
assert.equal(requests.length, 2);
assert.equal(
@@ -104,6 +109,8 @@ test("failed history loading pauses scroll requests until an explicit retry", as
"retry must request the failed page again",
);
assert.equal(state.error, undefined);
container.scrollTop = 20;
anchorTop = 360;
context.maybeLoadEarlierOnScroll(container);
assert.equal(requests.length, 2);
requests[1].resolve({
@@ -118,9 +125,15 @@ test("failed history loading pauses scroll requests until an explicit retry", as
},
});
await retry;
assert.equal(
container.scrollTop,
220,
"prepending history must preserve scrolling that continues during loading",
);
assert.equal(state.page, 2);
assert.equal(state.error, undefined);
assert.equal(records.session.length, 2);
container.scrollTop = 0;
context.maybeLoadEarlierOnScroll(container);
assert.equal(
requests.length,