新增虚拟滚动阈值逻辑以优化性能,改进可视化数据计算和滚动处理,确保在数据量较小时直接渲染全部数据。
This commit is contained in:
@@ -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}`,
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user