Навигация с клавиатуры
useVirtualKeyboardNav() — подключает обработчики keydown и управляет индексом в фокусе. Работает с любым компонентом виртуального списка.
ts
function useVirtualKeyboardNav(options: UseVirtualKeyboardNavOptions): UseVirtualKeyboardNavReturnОпции
itemCount
Ref<number> | number
Общее число элементов.
scrollTo
(index, align?) => void
Вызывается для прокрутки списка при смене фокуса.
target
Ref<HTMLElement | null> | HTMLElement · по умолчанию: document
Элемент, получающий события клавиатуры.
onActivate
(index: number) => void
Вызывается на Enter или Space.
onChange
(index: number) => void
Вызывается при смене индекса в фокусе.
loop
boolean · по умолчанию: false
Переходить ли на противоположный край при достижении границы.
Возвращаемое значение
focusedIndex
Readonly<Ref<number>>
Текущий индекс в фокусе, -1, если ничего не в фокусе.
setFocus
(index: number) => void
Программно установить фокус.
isFocused
(index: number) => boolean
В фокусе ли index.
Обрабатываемые клавиши
| Клавиша | Действие |
|---|---|
↑ | Переместить фокус вверх |
↓ | Переместить фокус вниз |
Home | Фокус на первый элемент |
End | Фокус на последний элемент |
PageUp | Прыжок на −10 элементов |
PageDown | Прыжок на +10 элементов |
Enter / Space | Вызвать onActivate |
Пример
vue
<script setup lang="ts">
import { computed, ref } from 'vue'
import { VirtualList, useVirtualKeyboardNav } from 'vue-virtual-scroller-kit'
import type { VirtualListExpose } from 'vue-virtual-scroller-kit'
const items = ref(Array.from({ length: 1000 }, (_, i) => ({ id: i, label: `Item ${i + 1}` })))
const listRef = ref<VirtualListExpose | null>(null)
const { focusedIndex, setFocus, isFocused } = useVirtualKeyboardNav({
itemCount: computed(() => items.value.length),
scrollTo: (i, align) => listRef.value?.scrollTo(i, align),
onActivate: (i) => console.log('Activated', items.value[i]),
loop: false,
})
</script>
<template>
<div tabindex="0" style="outline: none; border: 1px solid #ccc">
<VirtualList ref="listRef" :items="items" :estimated-item-size="48" style="height: 400px">
<template #default="{ item, index }">
<div
:class="{ focused: isFocused(index) }"
:aria-selected="isFocused(index)"
role="option"
@click="setFocus(index)"
>
{{ item.label }}
</div>
</template>
</VirtualList>
</div>
</template>