Клавиатурная навигация является важным аспектом интерактивных веб-приложений, обеспечивая доступность и удобство работы с интерфейсом без использования мыши. В Inferno, как и в других современных JavaScript-фреймворках, она реализуется через обработку событий клавиатуры и управление состоянием компонентов.
В Inferno события клавиатуры обрабатываются с помощью стандартных
обработчиков onKeyDown, onKeyUp и
onKeyPress. Отличие заключается в том, что обработчики
можно привязывать напрямую к компонентам, а не к DOM-элементам вручную,
что упрощает управление логикой.
Пример:
import { render } from 'inferno';
import { Component } from 'inferno';
class KeyboardExample extends Component {
constructor(props) {
super(props);
this.state = { message: '' };
}
handleKeyDown = (event) => {
switch(event.key) {
case 'ArrowUp':
this.setState({ message: 'Нажата стрелка вверх' });
break;
case 'ArrowDown':
this.setState({ message: 'Нажата стрелка вниз' });
break;
case 'Enter':
this.setState({ message: 'Нажат Enter' });
break;
default:
this.setState({ message: `Нажата клавиша ${event.key}` });
}
}
render() {
return (
<div tabIndex="0" onKeyD own={this.handleKeyDown} style={{ outline: 'none' }}>
<p>{this.state.message}</p>
<p>Фокус на этом блоке и используйте клавиши стрелок или Enter</p>
</div>
);
}
}
render(<KeyboardExample />, document.getElementById('app'));
Ключевые моменты:
tabIndex="0" делает элемент фокусируемым.style={{ outline: 'none' }} убирает
стандартное обрамление фокуса, чтобы стилизовать его по своему
усмотрению.Для клавиатурной навигации критически важно управлять фокусом элементов. Inferno позволяет обращаться к DOM через рефы.
class FocusExample extends Component {
constructor(props) {
super(props);
this.inputRef = null;
}
setInputRef = (el) => {
this.inputRef = el;
}
focusInput = () => {
if (this.inputRef) {
this.inputRef.focus();
}
}
render() {
return (
<div>
<input ref={this.setInputRef} type="text" placeholder="Введите текст" />
<button onCl ick={this.focusInput}>Сфокусировать input</button>
</div>
);
}
}
Особенности работы с фокусом:
focus() позволяет программно перемещать
фокус.createRef и
useRef при интеграции с хуками.Иногда требуется реагировать на комбинации клавиш, например, Ctrl+S
или Alt+Arrow. Это реализуется через проверку модификаторов
event.ctrlKey, event.altKey и
event.shiftKey.
handleKeyCombination = (event) => {
if (event.ctrlKey && event.key === 's') {
event.preventDefault();
console.log('Сохранение документа');
}
if (event.altKey && event.key === 'ArrowRight') {
console.log('Переход вперед');
}
}
Замечания по обработке комбинаций:
event.preventDefault() предотвращает
стандартное поведение браузера.event.key
чувствителен к Shift).Для сложных интерфейсов, таких как списки, таблицы или меню, создаются виртуальные клавиатурные схемы. Это структуры, которые описывают навигацию между элементами с помощью стрелок и клавиш Enter/Escape.
Пример реализации навигации в таблице:
class TableNavigation extends Component {
constructor(props) {
super(props);
this.state = { selectedRow: 0, selectedCol: 0 };
}
handleKeyDown = (event) => {
const { selectedRow, selectedCol } = this.state;
const rowCount = this.props.data.length;
const colCount = this.props.data[0].length;
switch(event.key) {
case 'ArrowUp':
this.setState({ selectedRow: Math.max(selectedRow - 1, 0) });
break;
case 'ArrowDown':
this.setState({ selectedRow: Math.min(selectedRow + 1, rowCount - 1) });
break;
case 'ArrowLeft':
this.setState({ selectedCol: Math.max(selectedCol - 1, 0) });
break;
case 'ArrowRight':
this.setState({ selectedCol: Math.min(selectedCol + 1, colCount - 1) });
break;
}
}
render() {
const { data } = this.props;
const { selectedRow, selectedCol } = this.state;
return (
<table tabIndex="0" onKeyD own={this.handleKeyDown} style={{ outline: 'none' }}>
<tbody>
{data.map((row, rIdx) => (
<tr key={rIdx}>
{row.map((cell, cIdx) => (
<td key={cIdx} style={{ background: rIdx === selectedRow && cIdx === selectedCol ? '#ccc' : 'transparent' }}>
{cell}
</td>
))}
</tr>
))}
</tbody>
</table>
);
}
}
Особенности виртуальных схем:
Для обеспечения доступности необходимо использовать:
aria-selected,
aria-activedescendant и role для обозначения
текущего состояния элементов.tabIndex.Пример с атрибутами ARIA:
<td
role="gridcell"
aria-selected={rIdx === selectedRow && cIdx === selectedCol}
tabIndex={rIdx === selectedRow && cIdx === selectedCol ? 0 : -1}
>
{cell}
</td>
Эти практики позволяют клавиатурной навигации быть совместимой с экранными читалками и другими вспомогательными технологиями.
Клавиатурная навигация в Inferno строится на сочетании стандартных событий клавиатуры, управления фокусом через рефы, обработки последовательностей клавиш и использования ARIA-атрибутов для доступности. При правильной архитектуре компонентов она обеспечивает быстрый и интуитивно понятный интерфейс для пользователей.