diff --git a/src/components/VirtualList.vue b/src/components/VirtualList.vue index cc0a12e..f6bea0e 100644 --- a/src/components/VirtualList.vue +++ b/src/components/VirtualList.vue @@ -93,7 +93,7 @@ const handleSelect = (item) => { // 点击处理 const handleClick = (item) => { - if (props.frozen) return // 如果列表被冻��,不响应点击 + if (props.frozen) return // 如果列表被冻结,不响应点击 handleSelect(item) // 点击时同时触发选中 emit('click', item) } @@ -155,21 +155,28 @@ function handleKeyDown(e) { } else if (e.key === 'ArrowUp' || e.key === 'ArrowDown') { e.preventDefault() + const isFirstItem = selectedIndex.value === 0 + const isLastItem = selectedIndex.value === props.data.length - 1 + + // 如果已经在第一项还按上键,或在最后一项还按下键,则不处理 + if ((e.key === 'ArrowUp' && isFirstItem) || + (e.key === 'ArrowDown' && isLastItem)) { + return + } + isKeyboardNavigating.value = true if (keyboardTimer) clearTimeout(keyboardTimer) - const containerTop = containerRef.value.scrollTop - const containerHeight = containerRef.value.clientHeight + const containerTop = containerRef.value?.scrollTop || 0 + const containerHeight = containerRef.value?.clientHeight || 0 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 - - if (itemTop < containerTop) { + if (itemTop < containerTop && containerRef.value) { containerRef.value.scrollTop = itemTop } } else { @@ -177,11 +184,9 @@ function handleKeyDown(e) { selectedIndex.value = nextIndex emit('select', { ...props.data[nextIndex], index: nextIndex }) - // 计算项目底部位置 const itemBottom = (nextIndex + 1) * totalItemHeight.value const scrollBottom = containerTop + containerHeight - - if (itemBottom > scrollBottom) { + if (itemBottom > scrollBottom && containerRef.value) { containerRef.value.scrollTop = itemBottom - containerHeight } }