Автодополнение
Условие
Поле поиска с выпадающим списком. Требования: · <input class="q">; список - <ul class="list"> с <li class="opt">; · подсказки запрашиваются функцией search(query), она возвращает промис; · запрос уходит с задержкой 50 мс после окончания ввода; · пустой запрос список не показывает и запрос не шлёт; · ответы на устаревшие запросы игнорируются; · ↓ и ↑ двигают выделение (класс "active"), Enter выбирает, Escape закрывает; · выбор кладёт значение в поле и закрывает список.
Что проверяют тесты
пустой запрос ничего не шлёт
показывает подсказки
схлопывает быстрый ввод
устаревший ответ не перетирает
стрелки и Enter выбирают
стрелки ходят по кругу
Escape закрывает
клик по подсказке выбирает
Как подойти
Самая частая задача на фронтовом лайвкодинге, и она проверяет сразу четыре вещи: debounce, гонку ответов, клавиатуру и сброс производных состояний. Порядок сдачи: сначала поле и список, потом задержка, потом гонка, потом клавиатура - так на любом таймере остаётся работающая версия. Счётчик держим в ref, потому что его изменение не должно вызывать рендер. Что назвать вслух как следующий шаг: закрытие по клику снаружи, aria-combobox с aria-activedescendant, отмена запроса через AbortController, подсветка совпадения.
Подсказки: 5
- Состояний четыре: запрос, список, открыт ли список, индекс выделения.
- Задержка живёт в эффекте: очистка эффекта отменяет прошлый таймер.
- От гонки спасает счётчик запросов в ref, а не флаг - запросов может быть много.
- Выделения может не быть вовсе (-1) - у стрелок вверх и вниз это разные стартовые случаи.
- При новом списке выделение надо сбрасывать, иначе индекс укажет в пустоту.
Решите в тренажёре
Редактор с автотестами прямо в браузере. Можно решить спокойно, вслух или под таймером, как на собесе.