Skip to content

Commit c71b494

Browse files
刘欢claude
andcommitted
fix: implement real nearest behavior with offset in Table scrollTo
- Fix nearest align to compute position after offset, then determine if scrolling is needed - Add align test buttons to scrollY and virtual demo files - Update center calculation formula Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 833f5ce commit c71b494

File tree

3 files changed

+64
-11
lines changed

3 files changed

+64
-11
lines changed

docs/examples/scrollY.tsx

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,27 @@ const Test = () => {
118118
>
119119
Scroll To key 9 (align: end)
120120
</button>
121+
<button
122+
onClick={() => {
123+
tblRef.current?.scrollTo({
124+
key: 9,
125+
align: 'nearest',
126+
});
127+
}}
128+
>
129+
Scroll To key 9 (align: nearest)
130+
</button>
131+
<button
132+
onClick={() => {
133+
tblRef.current?.scrollTo({
134+
index: 9,
135+
offset: 50,
136+
align: 'nearest',
137+
});
138+
}}
139+
>
140+
Scroll To index 9 + offset 50 (align: nearest)
141+
</button>
121142
<Table
122143
ref={tblRef}
123144
columns={columns}

docs/examples/virtual.tsx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,21 @@ const Demo: React.FC = () => {
205205
<button onClick={() => tableRef.current?.scrollTo({ key: '50', offset: -10 })}>
206206
Scroll To Key 50 + Offset -10
207207
</button>
208+
<button onClick={() => tableRef.current?.scrollTo({ index: 500, align: 'start' })}>
209+
index 500 + align start
210+
</button>
211+
<button onClick={() => tableRef.current?.scrollTo({ index: 500, align: 'end' })}>
212+
index 500 + align end
213+
</button>
214+
<button onClick={() => tableRef.current?.scrollTo({ index: 500, align: 'nearest' })}>
215+
index 500 + align nearest
216+
</button>
217+
<button onClick={() => tableRef.current?.scrollTo({ index: 500, offset: 50 })}>
218+
index 500 + offset 50
219+
</button>
220+
<button onClick={() => tableRef.current?.scrollTo({ index: 500, offset: 50, align: 'end' })}>
221+
index 500 + offset 50 + align end
222+
</button>
208223
<VirtualTable
209224
style={{ marginTop: 16 }}
210225
ref={tableRef}

src/Table.tsx

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@ const Table = <RecordType extends DefaultRecordType>(
351351
scrollTo: config => {
352352
if (scrollBodyRef.current instanceof HTMLElement) {
353353
// Native scroll
354-
const { index, top, key, offset, align = 'nearest' } = config;
354+
const { index, top, key, offset, align } = config;
355355

356356
if (validNumberValue(top)) {
357357
// In top mode, offset is ignored
@@ -363,21 +363,38 @@ const Table = <RecordType extends DefaultRecordType>(
363363
);
364364
if (targetElement) {
365365
if (!offset) {
366-
targetElement.scrollIntoView({ block: align });
366+
targetElement.scrollIntoView({ block: align ?? 'nearest' });
367367
} else {
368368
const container = scrollBodyRef.current;
369369
const elementTop = (targetElement as HTMLElement).offsetTop;
370370
const elementHeight = (targetElement as HTMLElement).offsetHeight;
371371
const containerHeight = container.clientHeight;
372-
373-
const alignMap: Record<ScrollLogicalPosition, number> = {
374-
start: elementTop,
375-
end: elementTop + elementHeight - containerHeight,
376-
center: elementTop + (elementHeight - containerHeight) / 2,
377-
nearest: elementTop,
378-
};
379-
const targetTop = alignMap[align] ?? elementTop;
380-
container.scrollTo({ top: targetTop + offset });
372+
const currentTop = container.scrollTop;
373+
const elementBottom = elementTop + elementHeight;
374+
const viewportBottom = currentTop + containerHeight;
375+
let targetTop: number;
376+
377+
if (align === 'nearest') {
378+
const targetWithOffset = elementTop + offset;
379+
const targetBottomWithOffset = elementBottom + offset;
380+
381+
if (targetWithOffset < currentTop) {
382+
targetTop = targetWithOffset;
383+
} else if (targetBottomWithOffset > viewportBottom) {
384+
targetTop = targetBottomWithOffset - containerHeight;
385+
} else {
386+
targetTop = currentTop;
387+
}
388+
} else {
389+
const alignMap: Record<string, number> = {
390+
start: elementTop,
391+
end: elementBottom - containerHeight,
392+
center: elementTop - (containerHeight - elementHeight) / 2,
393+
};
394+
targetTop = alignMap[align ?? 'start'] + offset;
395+
}
396+
397+
container.scrollTo({ top: targetTop });
381398
}
382399
}
383400
}

0 commit comments

Comments
 (0)