优化参数配置,简化组件构建
This commit is contained in:
13
src/App.vue
13
src/App.vue
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import ProjectList from './components/ProjectList.vue'
|
||||
import type { ListItem, MenuItem, ListConfig } from '@/types'
|
||||
import type { ListItem, MenuItem } from '@/types'
|
||||
|
||||
// 生成模拟数据
|
||||
const listData: ListItem[] = Array.from({ length: 789 }, (_, i) => ({
|
||||
@@ -15,14 +15,6 @@ const listData: ListItem[] = Array.from({ length: 789 }, (_, i) => ({
|
||||
]
|
||||
}))
|
||||
|
||||
// 自定义配置
|
||||
const listConfig: ListConfig = {
|
||||
itemHeight: 50,
|
||||
itemPadding: 16,
|
||||
bufferCount: 10,
|
||||
scrollDebounceTime: 16,
|
||||
}
|
||||
|
||||
// 自定义菜单项
|
||||
const menuItems: MenuItem[] = [
|
||||
{
|
||||
@@ -57,10 +49,7 @@ const handleItemClick = (item: ListItem): void => {
|
||||
<template>
|
||||
<ProjectList
|
||||
:data="listData"
|
||||
:config="listConfig"
|
||||
:menu-items="menuItems"
|
||||
:show-toolbar="true"
|
||||
:toolbar-height="40"
|
||||
@click="handleItemClick"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import VirtualList from './VirtualList.vue'
|
||||
import { ref, onMounted, onBeforeUnmount } from 'vue'
|
||||
import type { ListItem, MenuItem, ListConfig } from '@/types'
|
||||
import type { ListItem, MenuItem } from '@/types'
|
||||
|
||||
/**
|
||||
* 组件属性接口
|
||||
@@ -9,20 +9,17 @@ import type { ListItem, MenuItem, ListConfig } from '@/types'
|
||||
interface Props {
|
||||
/** 列表数据 */
|
||||
data: ListItem[]
|
||||
/** 虚拟列表配置 */
|
||||
config: ListConfig
|
||||
/** 菜单项配置 */
|
||||
menuItems: MenuItem[]
|
||||
/** 是否显示工具栏 */
|
||||
showToolbar?: boolean
|
||||
/** 工具栏高度 */
|
||||
toolbarHeight?: number
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
showToolbar: true,
|
||||
toolbarHeight: 40
|
||||
})
|
||||
const props = withDefaults(defineProps<Props>(), {})
|
||||
|
||||
// ===== 工具栏配置常量 =====
|
||||
/** 是否显示工具栏 */
|
||||
const SHOW_TOOLBAR = true
|
||||
/** 工具栏高度(像素) */
|
||||
const TOOLBAR_HEIGHT = 40
|
||||
|
||||
/**
|
||||
* 组件事件定义
|
||||
@@ -237,7 +234,6 @@ const onAfterLeave = (el: Element): void => {
|
||||
<div class="main-content">
|
||||
<VirtualList
|
||||
:data="data"
|
||||
:config="config"
|
||||
:frozen="listFrozen"
|
||||
:disable-hover="showMenu || temporaryDisableHover"
|
||||
@select="handleSelect"
|
||||
@@ -248,7 +244,7 @@ const onAfterLeave = (el: Element): void => {
|
||||
</div>
|
||||
|
||||
<!-- 工具栏 -->
|
||||
<div v-if="showToolbar" class="toolbar" :style="{ height: `${toolbarHeight}px` }">
|
||||
<div v-if="SHOW_TOOLBAR" class="toolbar" :style="{ height: `${TOOLBAR_HEIGHT}px` }">
|
||||
<div class="toolbar-content">
|
||||
<div class="total-count">共 {{ data.length }} 项</div>
|
||||
<div class="toolbar-spacer"></div>
|
||||
@@ -335,7 +331,7 @@ const onAfterLeave = (el: Element): void => {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
/* 弹性间隔:用于推开左右两侧的内容 */
|
||||
/* 弹性间隔:用<EFBFBD><EFBFBD>推开左右两侧的内容 */
|
||||
.toolbar-spacer {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted, onBeforeUnmount } from 'vue'
|
||||
import type { ListItem, ListConfig } from '@/types'
|
||||
import type { ListItem } from '@/types'
|
||||
|
||||
interface Props {
|
||||
data: ListItem[]
|
||||
config: ListConfig
|
||||
height?: string | number
|
||||
frozen?: boolean
|
||||
disableHover?: boolean
|
||||
@@ -23,9 +22,19 @@ const emit = defineEmits<{
|
||||
showToast: [message: string]
|
||||
}>()
|
||||
|
||||
// ===== 列表配置常量 =====
|
||||
/** 列表项基础高度(像素) */
|
||||
const ITEM_HEIGHT = 50
|
||||
/** 列表项内边距总和(像素) */
|
||||
const ITEM_PADDING = 16
|
||||
/** 上下缓冲区域的项目数量 */
|
||||
const BUFFER_COUNT = 10
|
||||
/** 滚动防抖时间(毫秒) */
|
||||
const SCROLL_DEBOUNCE_TIME = 16
|
||||
|
||||
// 计算列表项实际总高度
|
||||
const totalItemHeight = computed(() =>
|
||||
props.config.itemHeight + props.config.itemPadding
|
||||
ITEM_HEIGHT + ITEM_PADDING
|
||||
)
|
||||
|
||||
// 响应式状态管理
|
||||
@@ -46,10 +55,10 @@ const visibleCount = computed(() =>
|
||||
|
||||
// 计算当前需要渲染的数据
|
||||
const visibleData = computed(() => {
|
||||
const visibleStart = Math.max(0, startIndex.value - props.config.bufferCount)
|
||||
const visibleStart = Math.max(0, startIndex.value - BUFFER_COUNT)
|
||||
const visibleEnd = Math.min(
|
||||
props.data.length,
|
||||
startIndex.value + visibleCount.value + props.config.bufferCount
|
||||
startIndex.value + visibleCount.value + BUFFER_COUNT
|
||||
)
|
||||
|
||||
return props.data.slice(visibleStart, visibleEnd).map((item, index) => ({
|
||||
@@ -60,7 +69,7 @@ const visibleData = computed(() => {
|
||||
|
||||
// 计算列表偏移量
|
||||
const offsetY = computed(() =>
|
||||
Math.max(0, (startIndex.value - props.config.bufferCount) * totalItemHeight.value)
|
||||
Math.max(0, (startIndex.value - BUFFER_COUNT) * totalItemHeight.value)
|
||||
)
|
||||
|
||||
// 计算虚拟列表总高度
|
||||
@@ -117,7 +126,7 @@ function debounce<T extends (...args: any[]) => void>(fn: T, delay: number): (..
|
||||
|
||||
/**
|
||||
* 处理滚动事件(已防抖)
|
||||
* 根据滚动位置更新可视区域的起始索引
|
||||
* 根据滚动位置更新可视区<EFBFBD><EFBFBD>的起始索引
|
||||
*/
|
||||
const handleScroll = debounce(() => {
|
||||
if (!containerRef.value) return
|
||||
@@ -127,7 +136,7 @@ const handleScroll = debounce(() => {
|
||||
if (newStartIndex !== startIndex.value) {
|
||||
startIndex.value = newStartIndex
|
||||
}
|
||||
}, props.config.scrollDebounceTime)
|
||||
}, SCROLL_DEBOUNCE_TIME)
|
||||
|
||||
/** 鼠标悬停禁用状态 */
|
||||
const disableHover = ref<boolean>(false)
|
||||
@@ -293,7 +302,7 @@ onMounted(() => {
|
||||
|
||||
// 初始化容器高度
|
||||
updateContainerHeight()
|
||||
// 添加全局事件监听
|
||||
// 添加全局事<EFBFBD><EFBFBD>监听
|
||||
window.addEventListener('resize', updateContainerHeight)
|
||||
window.addEventListener('keydown', handleKeyDown)
|
||||
})
|
||||
@@ -341,7 +350,7 @@ onBeforeUnmount(() => {
|
||||
:key="item.index"
|
||||
class="list-item"
|
||||
:class="{ 'selected': selectedIndex === item.index }"
|
||||
:style="{ height: `${config.itemHeight}px` }"
|
||||
:style="{ height: `${ITEM_HEIGHT}px` }"
|
||||
@mouseenter="handleMouseEnter(item.index)"
|
||||
@click="handleClick(item)"
|
||||
@contextmenu="handleContextMenu($event, item)"
|
||||
|
||||
@@ -37,17 +37,3 @@ export interface MenuItem {
|
||||
/** 菜单项点击处理函数,接收当前选中的列表项作为参数 */
|
||||
action: (item: ListItem | null) => void
|
||||
}
|
||||
|
||||
/**
|
||||
* 虚拟列表配置接口
|
||||
*/
|
||||
export interface ListConfig {
|
||||
/** 列表项基础高度(像素) */
|
||||
itemHeight: number
|
||||
/** 列表项内边距总和(像素) */
|
||||
itemPadding: number
|
||||
/** 上下缓冲区域的项目数量 */
|
||||
bufferCount: number
|
||||
/** 滚动防抖时间(毫秒) */
|
||||
scrollDebounceTime: number
|
||||
}
|
||||
Reference in New Issue
Block a user