Skip to content

Навигация с клавиатуры

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>