Skip to content

Commit 60b1bbe

Browse files
authored
fix:当子节点过多时,滚动到最底部时,会产生闪烁
1 parent 7c0323a commit 60b1bbe

File tree

1 file changed

+41
-15
lines changed

1 file changed

+41
-15
lines changed

src/hooks/useVirtualList.ts

Lines changed: 41 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -47,26 +47,37 @@ export const useVirtualList = (nonReactive: INonReactiveData, props: IUseVirtual
4747
/**
4848
* 计算渲染的节点,基于 scrollTop 计算当前应该渲染哪些节点
4949
*/
50-
const updateRenderNodes = (isScroll: boolean = false): void => {
50+
function updateRenderNodes(isScroll: boolean = false): void {
51+
// 添加边界检查,防止无效更新
52+
if (blockLength.value === 0) return;
53+
5154
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+
}
5865
} else {
5966
renderStart.value = 0
6067
}
68+
69+
// 避免不必要的更新
6170
if (
6271
isScroll &&
6372
renderAmountCache.value === renderAmount.value &&
6473
renderStartCache.value === renderStart.value
65-
)
74+
) {
6675
return
76+
}
77+
6778
renderNodes.value = nonReactive.blockNodes
6879
.slice(renderStart.value, renderStart.value + renderAmount.value)
69-
.map(blockNode => {
80+
.map((blockNode: TreeNode) => {
7081
return Object.assign({}, blockNode, {
7182
_parent: null,
7283
children: []
@@ -105,15 +116,30 @@ export const useVirtualList = (nonReactive: INonReactiveData, props: IUseVirtual
105116
blockAreaHeight.value = props.nodeMinHeight * blockLength.value
106117
}
107118

108-
const handleTreeScroll = (): void => {
119+
//#endregion Calculate nodes
120+
const isThrottled = ref(false)
121+
122+
function handleTreeScroll(): void {
109123
if (debounceTimer.value) {
110124
window.cancelAnimationFrame(debounceTimer.value)
111125
}
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+
}
117143
}
118144

119145
/**

0 commit comments

Comments
 (0)