Skip to content

Commit 299eecf

Browse files
authored
Merge pull request #3117 from saifeiLee/2.38.3-alpha.3-tabs
fix(tabs): OverflowListFoundation实现防抖策略,避免某些宽度下的无限抖动循环
2 parents 8728fb0 + d102bbd commit 299eecf

File tree

1 file changed

+52
-1
lines changed

1 file changed

+52
-1
lines changed

packages/semi-foundation/overflowList/foundation.ts

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,18 @@ export interface OverflowListAdapter extends DefaultAdapter {
1111
getItemSizeMap: () => Map<string, number>
1212
}
1313

14+
// 防抖稳定性检测的时间阈值(毫秒)
15+
const STABILITY_THRESHOLD_MS = 150;
16+
1417
class OverflowListFoundation extends BaseFoundation<OverflowListAdapter> {
18+
// 记录上次的 overflow 结果,用于稳定性检测
19+
previousOverflowResult: Array<Array<Record<string, any>>> = [[], []];
20+
21+
// 记录每个 item 的状态变化历史(时间戳)
22+
stateChangeHistory: Map<string, number[]> = new Map();
23+
24+
// 最后一次稳定更新的时间戳
25+
lastStableUpdateTimestamp: number = 0;
1526

1627
constructor(adapter: OverflowListAdapter) {
1728
super({ ...adapter });
@@ -35,11 +46,51 @@ class OverflowListFoundation extends BaseFoundation<OverflowListAdapter> {
3546
const visibleStart = visibleStateArr.indexOf(true);
3647
const visibleEnd = visibleStateArr.lastIndexOf(true);
3748

38-
const overflowList = [];
49+
const overflowList: Array<Array<Record<string, any>>> = [];
3950
overflowList[0] = visibleStart >= 0 ? items.slice(0, visibleStart) : [];
4051
overflowList[1] = visibleEnd >= 0 ? items.slice(visibleEnd + 1, items.length) : items;
52+
53+
// 稳定性检测:比较新旧 overflow 结果
54+
const isResultChanged = this.isOverflowResultChanged(overflowList);
55+
56+
if (isResultChanged) {
57+
const now = Date.now();
58+
const timeSinceLastUpdate = now - this.lastStableUpdateTimestamp;
59+
60+
// 如果距离上次稳定更新时间太短,说明可能在抖动,返回上次稳定结果
61+
if (timeSinceLastUpdate < STABILITY_THRESHOLD_MS && this.previousOverflowResult[0].length + this.previousOverflowResult[1].length > 0) {
62+
return this.previousOverflowResult;
63+
}
64+
65+
// 更新稳定状态
66+
this.lastStableUpdateTimestamp = now;
67+
this.previousOverflowResult = overflowList;
68+
}
69+
4170
return overflowList;
4271
}
72+
73+
/**
74+
* 检查 overflow 结果是否发生变化
75+
*/
76+
isOverflowResultChanged(newResult: Array<Array<Record<string, any>>>): boolean {
77+
const prevLeft = this.previousOverflowResult[0];
78+
const prevRight = this.previousOverflowResult[1];
79+
const newLeft = newResult[0];
80+
const newRight = newResult[1];
81+
82+
if (prevLeft.length !== newLeft.length || prevRight.length !== newRight.length) {
83+
return true;
84+
}
85+
86+
// 比较 key 是否一致
87+
const prevLeftKeys = prevLeft.map(item => item.key).join(',');
88+
const prevRightKeys = prevRight.map(item => item.key).join(',');
89+
const newLeftKeys = newLeft.map(item => item.key).join(',');
90+
const newRightKeys = newRight.map(item => item.key).join(',');
91+
92+
return prevLeftKeys !== newLeftKeys || prevRightKeys !== newRightKeys;
93+
}
4394

4495
handleIntersect(entries: Array<IntersectionObserverEntry>): void {
4596
const visibleState = cloneDeep(this.getState('visibleState'));

0 commit comments

Comments
 (0)