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

Навигация с клавиатуры является важным аспектом интерактивных веб-приложений, обеспечивая доступность и удобство использования. В Vue.js это достигается за счёт реактивной модели данных и возможностей работы с событиями DOM.

Обработка событий клавиатуры

Для отслеживания нажатий клавиш используется директива v-on или её сокращение @. Основные события:

  • keydown — срабатывает при нажатии клавиши.
  • keyup — срабатывает при отпускании клавиши.
  • keypress — устаревшее событие для символов.

Пример базовой обработки:

<template>
  <input type="text" @keydown="handleKeydown" placeholder="Нажмите клавишу">
</template>

<script>
export default {
  methods: {
    handleKeydown(event) {
      console.log('Нажата клавиша:', event.key);
    }
  }
}
</script>

Ключевой момент: объект события event содержит информацию о нажатой клавише (key), её код (code) и модификаторы (ctrlKey, altKey, shiftKey, metaKey).

Модификаторы клавиш Vue

Vue.js предоставляет встроенные модификаторы для упрощения обработки клавиш:

  • .enter, .tab, .delete, .esc, .space, .up, .down, .left, .right.
  • .ctrl, .alt, .shift, .meta.

Пример использования модификаторов:

<button @keydown.enter="submitForm">Отправить</button>
<input @keydown.ctrl.enter="sendMessage">

Такое использование избавляет от необходимости вручную проверять event.key и улучшает читаемость кода.

Горячие клавиши и глобальные слушатели

Для реализации горячих клавиш можно использовать глобальные слушатели, добавляемые через mounted и удаляемые через beforeUnmount:

<script>
export default {
  mounted() {
    window.addEventListener('keydown', this.globalKeyHandler);
  },
  beforeUnmount() {
    window.removeEventListener('keydown', this.globalKeyHandler);
  },
  methods: {
    globalKeyHandler(event) {
      if (event.key === 'Escape') {
        this.closeModal();
      }
    },
    closeModal() {
      console.log('Модальное окно закрыто');
    }
  }
}
</script>

Это позволяет реагировать на клавиши независимо от того, какой элемент в фокусе.

Управление фокусом

Навигация с клавиатуры тесно связана с управлением фокусом элементов. В Vue.js реактивность позволяет динамически менять атрибут tabindex и использовать метод focus() для установки фокуса.

Пример управления фокусом:

<template>
  <input ref="inputField" type="text" placeholder="Фокус по кнопке">
  <button @click="focusInput">Фокус на поле</button>
</template>

<script>
export default {
  methods: {
    focusInput() {
      this.$refs.inputField.focus();
    }
  }
}
</script>

Использование tabindex:

<button :tabindex="isActive ? 0 : -1">Кнопка</button>

Элемент с tabindex="-1" исключается из обычной последовательности навигации клавиатурой.

Навигация по спискам и компонентам

Для сложных интерфейсов, например списков или таблиц, часто требуется перемещаться между элементами с помощью стрелок. Ключевые аспекты:

  • Хранение индекса текущего активного элемента в состоянии.
  • Обновление индекса при нажатии ArrowUp/ArrowDown.
  • Использование ref для установки фокуса на элемент по индексу.

Пример реализации:

<template>
  <ul>
    <li
      v-for="(item, index) in items"
      :key="item.id"
      :class="{ active: index === activeIndex }"
      ref="listItems"
      tabindex="0"
    >
      {{ item.name }}
    </li>
  </ul>
</template>

<script>
export default {
  data() {
    return {
      items: [{ id: 1, name: 'Элемент 1' }, { id: 2, name: 'Элемент 2' }],
      activeIndex: 0
    };
  },
  mounted() {
    this.$refs.listItems[this.activeIndex].focus();
  },
  methods: {
    handleKeydown(event) {
      if (event.key === 'ArrowDown' && this.activeIndex < this.items.length - 1) {
        this.activeIndex++;
      } else if (event.key === 'ArrowUp' && this.activeIndex > 0) {
        this.activeIndex--;
      }
      this.$refs.listItems[this.activeIndex].focus();
    }
  }
}
</script>

<style>
.active {
  background-color: #d3d3d3;
}
</style>

Доступность (Accessibility, a11y)

Для улучшения доступности при навигации с клавиатуры необходимо:

  • Использовать правильные роли ARIA (role="button", role="menu", aria-selected).
  • Обеспечивать логичную последовательность tabindex.
  • Обрабатывать события клавиш Enter и Space для интерактивных элементов, которые не являются стандартными кнопками.

Пример кнопки с ARIA:

<div role="button" tabindex="0" @keydown.enter="activate" @keydown.space.prevent="activate">
  Нажми меня
</div>

.prevent предотвращает стандартное поведение браузера при нажатии пробела, которое может вызвать прокрутку страницы.

Итоговые рекомендации

  • Использовать модификаторы клавиш Vue для упрощения кода.
  • Управлять фокусом через ref и tabindex.
  • Реализовывать глобальные горячие клавиши через mounted и beforeUnmount.
  • Проверять доступность через ARIA-атрибуты и последовательность tabindex.
  • Для списков и таблиц хранить индекс активного элемента и динамически обновлять фокус.

Навигация с клавиатуры во Vue.js становится мощным инструментом, когда объединяются реактивность, управление событиями и контроль фокуса, обеспечивая как удобство работы, так и доступность интерфейса.