diff --git a/src/App.vue b/src/App.vue index 589a2fa..4edbdc3 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,6 +1,6 @@ - + @@ -59,14 +116,28 @@ const toggleMenu = () => { 共 {{ listData.length }} 项 - + - + + + + {{ selectedItem.name }} + {{ selectedItem.path }} + + diff --git a/src/components/VirtualList.vue b/src/components/VirtualList.vue index b5c3704..cc0a12e 100644 --- a/src/components/VirtualList.vue +++ b/src/components/VirtualList.vue @@ -21,10 +21,14 @@ const props = defineProps({ height: { type: [String, Number], default: '100%' + }, + frozen: { + type: Boolean, + default: false } }) -const emit = defineEmits(['select']) +const emit = defineEmits(['select', 'click', 'contextmenu']) // 计算列表项实际总高度 const totalItemHeight = computed(() => @@ -82,10 +86,18 @@ const phantomHeight = computed(() => // 选择处理 const handleSelect = (item) => { + if (props.frozen) return // 如果列表被冻结,不响应选择 selectedIndex.value = item.index emit('select', item) } +// 点击处理 +const handleClick = (item) => { + if (props.frozen) return // 如果列表被冻��,不响应点击 + handleSelect(item) // 点击时同时触发选中 + emit('click', item) +} + // 修改更新容器高度的方法 function updateContainerHeight() { if (containerRef.value) { @@ -123,16 +135,24 @@ const handleScroll = debounce(() => { // 鼠标移入处理 function handleMouseEnter(index) { + if (props.frozen) return // 如果列表被冻结,不响应鼠标移入 if (!isKeyboardNavigating.value) { selectedIndex.value = index - // 移除滚动检查和处理,直接调用确保可见的方法 + emit('select', { ...props.data[index], index }) ensureSelectedItemVisible() } } // 键盘事件处理 function handleKeyDown(e) { - if (e.key === 'ArrowUp' || e.key === 'ArrowDown') { + if (props.frozen) return // 如果列表被冻结,不响应键盘事件 + if (e.key === 'Enter') { + // 回车键触发点击事件 + if (selectedIndex.value >= 0 && selectedIndex.value < props.data.length) { + const item = props.data[selectedIndex.value] + emit('click', { ...item, index: selectedIndex.value }) + } + } else if (e.key === 'ArrowUp' || e.key === 'ArrowDown') { e.preventDefault() isKeyboardNavigating.value = true @@ -144,6 +164,7 @@ function handleKeyDown(e) { if (e.key === 'ArrowUp') { const nextIndex = Math.max(0, selectedIndex.value - 1) selectedIndex.value = nextIndex + emit('select', { ...props.data[nextIndex], index: nextIndex }) // 使用与向下相同的逻辑,计算项目顶部位置 const itemTop = nextIndex * totalItemHeight.value @@ -154,6 +175,7 @@ function handleKeyDown(e) { } else { const nextIndex = Math.min(props.data.length - 1, selectedIndex.value + 1) selectedIndex.value = nextIndex + emit('select', { ...props.data[nextIndex], index: nextIndex }) // 计算项目底部位置 const itemBottom = (nextIndex + 1) * totalItemHeight.value @@ -191,6 +213,13 @@ function ensureSelectedItemVisible() { } } +// 修改右键点击处理函数 +const handleContextMenu = (e, item) => { + if (props.frozen) return // 如果列表被冻结,不响应右键点击 + e.preventDefault() // 阻止默认右键菜单 + emit('contextmenu', { item }) // 不需要传递事件对象 +} + onMounted(() => { if (containerRef.value) { containerRef.value.addEventListener('scroll', handleScroll) @@ -233,6 +262,7 @@ onBeforeUnmount(() => { @@ -252,7 +282,8 @@ onBeforeUnmount(() => { :class="{ 'selected': selectedIndex === item.index }" :style="{ height: `${config.itemHeight}px` }" @mouseenter="handleMouseEnter(item.index)" - @click="handleSelect(item)" + @click="handleClick(item)" + @contextmenu="handleContextMenu($event, item)" > @@ -300,7 +331,7 @@ onBeforeUnmount(() => { padding: 8px 16px; display: flex; align-items: center; - transition: background-color 0.8s ease; + transition: background-color 0.2s ease, opacity 0.2s ease; cursor: pointer; background-color: white; } @@ -348,4 +379,11 @@ onBeforeUnmount(() => { overflow: hidden; text-overflow: ellipsis; } + +/* 添加冻结状态的样式 */ +.list-frozen { + pointer-events: none; /* 禁用鼠标事件 */ + opacity: 0.7; /* 降低透明度表示冻结状态 */ + user-select: none; /* 禁用文本选择 */ +} \ No newline at end of file