@@ -47,26 +47,37 @@ export const useVirtualList = (nonReactive: INonReactiveData, props: IUseVirtual
47
47
/**
48
48
* 计算渲染的节点,基于 scrollTop 计算当前应该渲染哪些节点
49
49
*/
50
- const updateRenderNodes = ( isScroll : boolean = false ) : void => {
50
+ function updateRenderNodes ( isScroll : boolean = false ) : void {
51
+ // 添加边界检查,防止无效更新
52
+ if ( blockLength . value === 0 ) return ;
53
+
51
54
if ( blockLength . value > renderAmount . value ) {
52
- const scrollTop = Math . max ( scrollArea . value . scrollTop , 0 )
53
- /** 当前滚动了多少节点 */
54
- const scrollNodeAmount = Math . floor ( scrollTop / props . nodeMinHeight )
55
- renderStart . value =
56
- Math . floor ( scrollNodeAmount / props . bufferNodeAmount ) *
57
- props . bufferNodeAmount
55
+ const scrollTop = scrollArea . value . scrollTop
56
+ const maxScrollTop = blockAreaHeight . value - scrollArea . value . clientHeight
57
+
58
+ // 添加滚动到底部的判断
59
+ if ( scrollTop >= maxScrollTop ) {
60
+ renderStart . value = Math . max ( 0 , blockLength . value - renderAmount . value )
61
+ } else {
62
+ const scrollNodeAmount = Math . floor ( scrollTop / props . nodeMinHeight )
63
+ renderStart . value = Math . floor ( scrollNodeAmount / props . bufferNodeAmount ) * props . bufferNodeAmount
64
+ }
58
65
} else {
59
66
renderStart . value = 0
60
67
}
68
+
69
+ // 避免不必要的更新
61
70
if (
62
71
isScroll &&
63
72
renderAmountCache . value === renderAmount . value &&
64
73
renderStartCache . value === renderStart . value
65
- )
74
+ ) {
66
75
return
76
+ }
77
+
67
78
renderNodes . value = nonReactive . blockNodes
68
79
. slice ( renderStart . value , renderStart . value + renderAmount . value )
69
- . map ( blockNode => {
80
+ . map ( ( blockNode : TreeNode ) => {
70
81
return Object . assign ( { } , blockNode , {
71
82
_parent : null ,
72
83
children : [ ]
@@ -105,15 +116,30 @@ export const useVirtualList = (nonReactive: INonReactiveData, props: IUseVirtual
105
116
blockAreaHeight . value = props . nodeMinHeight * blockLength . value
106
117
}
107
118
108
- const handleTreeScroll = ( ) : void => {
119
+ //#endregion Calculate nodes
120
+ const isThrottled = ref ( false )
121
+
122
+ function handleTreeScroll ( ) : void {
109
123
if ( debounceTimer . value ) {
110
124
window . cancelAnimationFrame ( debounceTimer . value )
111
125
}
112
- renderAmountCache . value = renderAmount . value
113
- renderStartCache . value = renderStart . value
114
- debounceTimer . value = window . requestAnimationFrame (
115
- updateRenderNodes . bind ( null , true )
116
- )
126
+
127
+ // 添加节流
128
+ if ( ! isThrottled . value ) {
129
+ isThrottled . value = true
130
+
131
+ renderAmountCache . value = renderAmount . value
132
+ renderStartCache . value = renderStart . value
133
+
134
+ debounceTimer . value = window . requestAnimationFrame ( ( ) => {
135
+ updateRenderNodes ( true )
136
+
137
+ // 重置节流状态
138
+ setTimeout ( ( ) => {
139
+ isThrottled . value = false
140
+ } , 16 ) // 约60fps
141
+ } )
142
+ }
117
143
}
118
144
119
145
/**
0 commit comments