新增虚拟滚动阈值逻辑以优化性能,改进可视化数据计算和滚动处理,确保在数据量较小时直接渲染全部数据。

This commit is contained in:
2024-12-11 15:49:05 +08:00
parent 0a8af1d97b
commit d218789c2b
2 changed files with 34 additions and 8 deletions

View File

@@ -3,7 +3,7 @@ import ProjectList from './components/ProjectList.vue'
import type { ListItem, MenuItem } from '@/types'
// 生成模拟数据
const listData: ListItem[] = Array.from({ length: 789 }, (_, i) => ({
const listData: ListItem[] = Array.from({ length: 50 }, (_, i) => ({
id: i,
name: `project-${i + 1}`,
path: `/Users/lanyuanxiaoyao/Project/IdeaProjects/project-${i + 1}`,

View File

@@ -31,6 +31,8 @@ const ITEM_PADDING = 16
const BUFFER_COUNT = 10
/** 滚动防抖时间(毫秒) */
const SCROLL_DEBOUNCE_TIME = 16
/** 虚拟滚动阈值,少于此数量则直接渲染全部 */
const VIRTUALIZATION_THRESHOLD = 500
// 计算列表项实际总高度
const totalItemHeight = computed(() =>
@@ -53,8 +55,25 @@ const visibleCount = computed(() =>
Math.floor(containerHeight.value / totalItemHeight.value)
)
/**
* 是否需要虚拟滚动
* 当数据量小于阈值时直接渲染全部
*/
const needVirtualization = computed<boolean>(() =>
props.data.length > VIRTUALIZATION_THRESHOLD
)
// 计算当前需要渲染的数据
const visibleData = computed(() => {
// 数据量小于阈值时,直接返回全部数据
if (!needVirtualization.value) {
return props.data.map((item, index) => ({
...item,
index
}))
}
// 否则使用虚拟滚动
const visibleStart = Math.max(0, startIndex.value - BUFFER_COUNT)
const visibleEnd = Math.min(
props.data.length,
@@ -69,12 +88,16 @@ const visibleData = computed(() => {
// 计算列表偏移量
const offsetY = computed(() =>
Math.max(0, (startIndex.value - BUFFER_COUNT) * totalItemHeight.value)
needVirtualization.value
? Math.max(0, (startIndex.value - BUFFER_COUNT) * totalItemHeight.value)
: 0
)
// 计算虚拟列表总高度
const phantomHeight = computed(() =>
props.data.length * totalItemHeight.value
needVirtualization.value
? props.data.length * totalItemHeight.value
: 'auto'
)
// 选择处理
@@ -126,9 +149,12 @@ function debounce<T extends (...args: any[]) => void>(fn: T, delay: number): (..
/**
* 处理滚动事件(已防抖)
* 根据滚动位置更新可视区<EFBFBD><EFBFBD>的起始索引
* 根据滚动位置更新可视区的起始索引
*/
const handleScroll = debounce(() => {
// 不需要虚拟滚动时直接返回
if (!needVirtualization.value) return
if (!containerRef.value) return
const scrollTop = containerRef.value.scrollTop
const newStartIndex = Math.floor(scrollTop / totalItemHeight.value)
@@ -253,7 +279,7 @@ function handleKeyDown(e: KeyboardEvent): void {
}
/**
* 保选中项在可视区域内
* 保选中项在可视区域内
* 如果选中项不可见,则滚动到合适位置
*/
function ensureSelectedItemVisible(): void {
@@ -302,7 +328,7 @@ onMounted(() => {
// 初始化容器高度
updateContainerHeight()
// 添加全局事<EFBFBD><EFBFBD>监听
// 添加全局事监听
window.addEventListener('resize', updateContainerHeight)
window.addEventListener('keydown', handleKeyDown)
})
@@ -337,12 +363,12 @@ onBeforeUnmount(() => {
<div
ref="listRef"
class="virtual-list-phantom"
:style="{ height: `${phantomHeight}px` }"
:style="{ height: needVirtualization ? `${phantomHeight}px` : 'auto' }"
>
<!-- 实际渲染的列表内容 -->
<div
class="virtual-list"
:style="{ transform: `translateY(${offsetY}px)` }"
:style="needVirtualization ? { transform: `translateY(${offsetY}px)` } : {}"
>
<!-- 列表项 -->
<div