diff --git a/src/App.vue b/src/App.vue index 45e4674..41e0d39 100644 --- a/src/App.vue +++ b/src/App.vue @@ -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}`, diff --git a/src/components/VirtualList.vue b/src/components/VirtualList.vue index d77f035..81e9ffd 100644 --- a/src/components/VirtualList.vue +++ b/src/components/VirtualList.vue @@ -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(() => + 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 void>(fn: T, delay: number): (.. /** * 处理滚动事件(已防抖) - * 根据滚动位置更新可视区��的起始索引 + * 根据滚动位置更新可视区的起始索引 */ 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() - // 添加全局事��监听 + // 添加全局事件监听 window.addEventListener('resize', updateContainerHeight) window.addEventListener('keydown', handleKeyDown) }) @@ -337,12 +363,12 @@ onBeforeUnmount(() => {