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

Mithril — легковесный JavaScript-фреймворк для создания одностраничных приложений (SPA), предоставляющий минимальный, но мощный API. Работа с навигацией в SPA часто требует внимания к клавиатурной интерактивности, особенно для обеспечения доступности и удобства управления без мыши. Mithril предоставляет возможности для управления состоянием приложения и навигации с клавиатуры через работу с маршрутизатором (m.route) и обработчиками событий.


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

Фокусировка элементов — ключевой аспект клавиатурной навигации. В HTML это достигается с помощью атрибутов tabindex и методов focus().

m('input', { tabindex: 0, onkeydown: (e) => {
    if (e.key === 'Enter') e.target.focus();
}})

Особенности в Mithril:

  • oncreate и onupdate позволяют управлять фокусом после создания или обновления элемента.
  • Использование ref через функцию или объект позволяет сохранять ссылку на DOM-узел для программного фокуса:
let inputRef;

m('input', {
    oncreate: ({ dom }) => dom.focus(),
    onupdate: ({ dom }) => dom.focus(),
    onkeydown: (e) => {
        if (e.key === 'Tab') {
            // логика переключения фокуса
        }
    },
    ref: (el) => inputRef = el
})

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

События keydown, keyup и keypress являются основой клавиатурной навигации. Mithril позволяет назначать их напрямую через объект атрибутов:

m('div', {
    tabindex: 0,
    onkeydown: (e) => {
        switch(e.key) {
            case 'ArrowUp':
                // перемещение вверх
                break;
            case 'ArrowDown':
                // перемещение вниз
                break;
            case 'Enter':
                // подтверждение действия
                break;
        }
    }
})

Рекомендации:

  • Использовать tabindex="0" для элементов, которые должны быть доступными для клавиатуры.
  • Обрабатывать комбинации клавиш с помощью e.shiftKey, e.ctrlKey и e.altKey.
  • Событие preventDefault() предотвращает стандартное поведение браузера, когда это необходимо.

Навигация между компонентами

В SPA часто возникает задача перемещения фокуса между компонентами без перезагрузки страницы. В Mithril это реализуется через маршруты и виртуальные DOM-деревья.

m.route(document.body, "/home", {
    "/home": HomeComponent,
    "/about": AboutComponent
});

function HomeComponent() {
    return m('div', [
        m('button', { onkeydown: handleKey }, 'Перейти к About')
    ]);
}

function handleKey(e) {
    if (e.key === 'Enter') m.route.set('/about');
}

Примечание: m.route.set() изменяет URL и обновляет отображаемый компонент без полной перезагрузки страницы.


Управление списками и таблицами

При создании интерактивных списков и таблиц важно правильно реализовать клавиатурное перемещение:

let selectedIndex = 0;
const items = ['Элемент 1', 'Элемент 2', 'Элемент 3'];

function ListComponent() {
    return m('ul', items.map((item, index) =>
        m('li', {
            tabindex: 0,
            class: selectedIndex === index ? 'active' : '',
            onkeydown: (e) => {
                if (e.key === 'ArrowDown') selectedIndex = (selectedIndex + 1) % items.length;
                if (e.key === 'ArrowUp') selectedIndex = (selectedIndex - 1 + items.length) % items.length;
            },
            oncreate: ({ dom }) => {
                if (index === selectedIndex) dom.focus();
            }
        }, item)
    ));
}

Ключевые моменты:

  • Использование циклической логики при перемещении вверх/вниз обеспечивает бесконечное прокручивание.
  • В oncreate можно сразу выставлять фокус на активный элемент.
  • Классы позволяют визуально подсветить текущий элемент.

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

Навигация с клавиатуры напрямую связана с доступностью. В Mithril следует:

  • Использовать семантические HTML-элементы (button, a, input) для автоматической поддержки клавиатуры.
  • Добавлять aria-* атрибуты для динамических компонентов, например:
m('div', {
    role: 'menu',
    'aria-activedescendant': `item-${selectedIndex}`
}, items.map((item, index) =>
    m('div', { id: `item-${index}`, role: 'menuitem' }, item)
));
  • Обновлять состояние с помощью onupdate для правильного управления фокусом.

Сочетание с формами и модальными окнами

Фокусировка и клавиатурное управление критичны в формах и модальных компонентах. Mithril позволяет управлять этим через комбинацию oncreate, onupdate и onkeydown:

function Modal() {
    let inputRef;

    return m('div.modal', {
        onkeydown: (e) => {
            if (e.key === 'Escape') closeModal();
        },
        oncreate: () => inputRef.focus()
    }, [
        m('input', { ref: el => inputRef = el, tabindex: 0 })
    ]);
}

Особенности:

  • Escape закрывает модальные окна.
  • Первый элемент формы получает фокус автоматически.
  • ref используется для сохранения ссылки на DOM-элемент.

Итоги технических подходов

  1. tabindex и методы focus() управляют фокусом.
  2. onkeydown позволяет отслеживать и обрабатывать клавиши.
  3. m.route.set() управляет переходами между страницами без перезагрузки.
  4. oncreate и onupdate обеспечивают актуальный фокус и визуальные подсветки.
  5. Семантическая разметка и aria-* атрибуты повышают доступность.

Навигация с клавиатуры в Mithril требует внимательного сочетания событий, фокуса и маршрутизации, но правильное использование этих инструментов обеспечивает удобное и доступное SPA.