优化参数配置,简化组件构建

This commit is contained in:
2024-12-11 15:40:44 +08:00
parent 812a642aaa
commit 0a8af1d97b
4 changed files with 31 additions and 51 deletions

View File

@@ -1,6 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import ProjectList from './components/ProjectList.vue' 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) => ({ 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[] = [ const menuItems: MenuItem[] = [
{ {
@@ -57,10 +49,7 @@ const handleItemClick = (item: ListItem): void => {
<template> <template>
<ProjectList <ProjectList
:data="listData" :data="listData"
:config="listConfig"
:menu-items="menuItems" :menu-items="menuItems"
:show-toolbar="true"
:toolbar-height="40"
@click="handleItemClick" @click="handleItemClick"
/> />
</template> </template>

View File

@@ -1,7 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import VirtualList from './VirtualList.vue' import VirtualList from './VirtualList.vue'
import { ref, onMounted, onBeforeUnmount } from '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 { interface Props {
/** 列表数据 */ /** 列表数据 */
data: ListItem[] data: ListItem[]
/** 虚拟列表配置 */
config: ListConfig
/** 菜单项配置 */ /** 菜单项配置 */
menuItems: MenuItem[] menuItems: MenuItem[]
/** 是否显示工具栏 */
showToolbar?: boolean
/** 工具栏高度 */
toolbarHeight?: number
} }
const props = withDefaults(defineProps<Props>(), { const props = withDefaults(defineProps<Props>(), {})
showToolbar: true,
toolbarHeight: 40 // ===== 工具栏配置常量 =====
}) /** 是否显示工具栏 */
const SHOW_TOOLBAR = true
/** 工具栏高度(像素) */
const TOOLBAR_HEIGHT = 40
/** /**
* 组件事件定义 * 组件事件定义
@@ -237,7 +234,6 @@ const onAfterLeave = (el: Element): void => {
<div class="main-content"> <div class="main-content">
<VirtualList <VirtualList
:data="data" :data="data"
:config="config"
:frozen="listFrozen" :frozen="listFrozen"
:disable-hover="showMenu || temporaryDisableHover" :disable-hover="showMenu || temporaryDisableHover"
@select="handleSelect" @select="handleSelect"
@@ -248,7 +244,7 @@ const onAfterLeave = (el: Element): void => {
</div> </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="toolbar-content">
<div class="total-count"> {{ data.length }} </div> <div class="total-count"> {{ data.length }} </div>
<div class="toolbar-spacer"></div> <div class="toolbar-spacer"></div>
@@ -335,7 +331,7 @@ const onAfterLeave = (el: Element): void => {
color: #666; color: #666;
} }
/* 弹性间隔:用推开左右两侧的内容 */ /* 弹性间隔:用<EFBFBD><EFBFBD>推开左右两侧的内容 */
.toolbar-spacer { .toolbar-spacer {
flex: 1; flex: 1;
} }

View File

@@ -1,10 +1,9 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, computed, onMounted, onBeforeUnmount } from 'vue' import { ref, computed, onMounted, onBeforeUnmount } from 'vue'
import type { ListItem, ListConfig } from '@/types' import type { ListItem } from '@/types'
interface Props { interface Props {
data: ListItem[] data: ListItem[]
config: ListConfig
height?: string | number height?: string | number
frozen?: boolean frozen?: boolean
disableHover?: boolean disableHover?: boolean
@@ -23,9 +22,19 @@ const emit = defineEmits<{
showToast: [message: string] showToast: [message: string]
}>() }>()
// ===== 列表配置常量 =====
/** 列表项基础高度(像素) */
const ITEM_HEIGHT = 50
/** 列表项内边距总和(像素) */
const ITEM_PADDING = 16
/** 上下缓冲区域的项目数量 */
const BUFFER_COUNT = 10
/** 滚动防抖时间(毫秒) */
const SCROLL_DEBOUNCE_TIME = 16
// 计算列表项实际总高度 // 计算列表项实际总高度
const totalItemHeight = computed(() => const totalItemHeight = computed(() =>
props.config.itemHeight + props.config.itemPadding ITEM_HEIGHT + ITEM_PADDING
) )
// 响应式状态管理 // 响应式状态管理
@@ -46,10 +55,10 @@ const visibleCount = computed(() =>
// 计算当前需要渲染的数据 // 计算当前需要渲染的数据
const visibleData = 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( const visibleEnd = Math.min(
props.data.length, 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) => ({ return props.data.slice(visibleStart, visibleEnd).map((item, index) => ({
@@ -60,7 +69,7 @@ const visibleData = computed(() => {
// 计算列表偏移量 // 计算列表偏移量
const offsetY = 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(() => { const handleScroll = debounce(() => {
if (!containerRef.value) return if (!containerRef.value) return
@@ -127,7 +136,7 @@ const handleScroll = debounce(() => {
if (newStartIndex !== startIndex.value) { if (newStartIndex !== startIndex.value) {
startIndex.value = newStartIndex startIndex.value = newStartIndex
} }
}, props.config.scrollDebounceTime) }, SCROLL_DEBOUNCE_TIME)
/** 鼠标悬停禁用状态 */ /** 鼠标悬停禁用状态 */
const disableHover = ref<boolean>(false) const disableHover = ref<boolean>(false)
@@ -293,7 +302,7 @@ onMounted(() => {
// 初始化容器高度 // 初始化容器高度
updateContainerHeight() updateContainerHeight()
// 添加全局事监听 // 添加全局事<EFBFBD><EFBFBD>监听
window.addEventListener('resize', updateContainerHeight) window.addEventListener('resize', updateContainerHeight)
window.addEventListener('keydown', handleKeyDown) window.addEventListener('keydown', handleKeyDown)
}) })
@@ -341,7 +350,7 @@ onBeforeUnmount(() => {
:key="item.index" :key="item.index"
class="list-item" class="list-item"
:class="{ 'selected': selectedIndex === item.index }" :class="{ 'selected': selectedIndex === item.index }"
:style="{ height: `${config.itemHeight}px` }" :style="{ height: `${ITEM_HEIGHT}px` }"
@mouseenter="handleMouseEnter(item.index)" @mouseenter="handleMouseEnter(item.index)"
@click="handleClick(item)" @click="handleClick(item)"
@contextmenu="handleContextMenu($event, item)" @contextmenu="handleContextMenu($event, item)"

View File

@@ -37,17 +37,3 @@ export interface MenuItem {
/** 菜单项点击处理函数,接收当前选中的列表项作为参数 */ /** 菜单项点击处理函数,接收当前选中的列表项作为参数 */
action: (item: ListItem | null) => void action: (item: ListItem | null) => void
} }
/**
* 虚拟列表配置接口
*/
export interface ListConfig {
/** 列表项基础高度(像素) */
itemHeight: number
/** 列表项内边距总和(像素) */
itemPadding: number
/** 上下缓冲区域的项目数量 */
bufferCount: number
/** 滚动防抖时间(毫秒) */
scrollDebounceTime: number
}