Skip to content

Commit 2344222

Browse files
committed
refactor: 优化虚拟列表性能和滚动体验
1 parent 022bf0d commit 2344222

File tree

4 files changed

+786
-64
lines changed

4 files changed

+786
-64
lines changed

.vscode/settings.json

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,6 @@
1212
"[json]": {
1313
"editor.defaultFormatter": "esbenp.prettier-vscode"
1414
},
15-
// md 文件按 prettier 规范格式化
16-
"[md]": {
17-
"editor.defaultFormatter": "esbenp.prettier-vscode"
18-
},
1915
"prettier.printWidth": 180,
2016

2117
// Enable eslint for all supported languages
@@ -24,6 +20,6 @@
2420
"javascriptreact",
2521
"typescript",
2622
"typescriptreact",
27-
"vue",
23+
"vue"
2824
]
2925
}

components/virtual-list/listItem.ts

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* item component, we need to know their size change at any time
33
*/
44

5-
import { cloneVNode, computed, defineComponent, ref } from 'vue';
5+
import { cloneVNode, computed, defineComponent, onBeforeUnmount, ref } from 'vue';
66
import useResize from '../_util/use/useResize';
77
import { getFirstValidNode } from '../_util/vnode';
88
import getElementFromVueInstance from '../_util/getElementFromVueInstance';
@@ -14,20 +14,51 @@ export const FVirtualListItem = defineComponent({
1414
props: itemProps,
1515
setup(props, { attrs }) {
1616
const itemRef = ref();
17+
let lastReportedSize = 0;
18+
let sizeCheckTimer: number | null = null;
1719

18-
// tell parent current size identify by unqiue key
20+
// 优化的尺寸变化检测和上报
1921
const dispatchSizeChange = () => {
22+
if (!itemRef.value) {
23+
return;
24+
}
25+
2026
const shapeKey = props.horizontal ? 'offsetWidth' : 'offsetHeight';
21-
const s = itemRef.value ? itemRef.value[shapeKey] : 0;
22-
(attrs as any).onItemResized(props.uniqueKey, s);
27+
const currentSize = itemRef.value[shapeKey] || 0;
28+
29+
// 只有当尺寸显著变化时才上报,避免频繁的微小变化
30+
// 阈值可以根据实际情况调整,例如设置为2px
31+
const sizeThreshold = 2;
32+
if (Math.abs(currentSize - lastReportedSize) >= sizeThreshold) {
33+
lastReportedSize = currentSize;
34+
(attrs as any).onItemResized(props.uniqueKey, currentSize);
35+
}
2336
};
2437

38+
// 防抖的尺寸检查,并确保在组件卸载时清除定时器
39+
const debouncedSizeCheck = () => {
40+
if (sizeCheckTimer) {
41+
clearTimeout(sizeCheckTimer);
42+
}
43+
// 稍微增加延迟,减少高频触发,例如 30ms
44+
sizeCheckTimer = setTimeout(dispatchSizeChange, 16) as any;
45+
};
46+
47+
// 使用原有的useResize,但添加防抖
2548
useResize(
2649
itemRef,
27-
dispatchSizeChange,
50+
debouncedSizeCheck,
2851
computed(() => !props.observeResize),
2952
);
3053

54+
// 清理定时器
55+
onBeforeUnmount(() => {
56+
if (sizeCheckTimer) {
57+
clearTimeout(sizeCheckTimer);
58+
sizeCheckTimer = null;
59+
}
60+
});
61+
3162
return {
3263
itemRef,
3364
};

0 commit comments

Comments
 (0)