Navigo — это легковесная библиотека маршрутизации для JavaScript, обеспечивающая работу с клиентскими маршрутами и управление переходами между состояниями приложения. При работе с динамическим контентом, который загружается асинхронно, крайне важно обеспечивать пользователю визуальную обратную связь о процессе загрузки. Для этого используются индикаторы загрузки (loading indicators), которые информируют о том, что данные находятся в процессе получения или обработки.
Индикатор загрузки обычно представляет собой DOM-элемент, который отображается при начале асинхронной операции и скрывается после её завершения. Простейшая реализация может выглядеть так:
const loader = document.createElement('div');
loader.id = 'loader';
loader.textContent = 'Загрузка...';
loader.style.display = 'none';
document.body.appendChild(loader);
function showLoader() {
loader.style.display = 'block';
}
function hideLoader() {
loader.style.display = 'none';
}
Здесь showLoader() и hideLoader() управляют
видимостью индикатора. В реальных приложениях можно использовать
CSS-анимации, спиннеры или прогресс-бары для улучшения визуального
эффекта.
Navigo позволяет назначать обработчики для маршрутов через метод
on(). Для интеграции индикатора загрузки необходимо
оборачивать асинхронные функции, которые подгружают данные, в вызовы
showLoader() и hideLoader(). Пример:
const router = new Navigo('/', { hash: true });
router.on('/users', async () => {
showLoader();
try {
const response = await fetch('/api/users');
const users = await response.json();
renderUsers(users);
} catch (error) {
console.error(error);
renderError(error);
} finally {
hideLoader();
}
});
router.resolve();
В этом примере индикатор отображается до момента завершения
асинхронного запроса и скрывается в блоке finally, что
гарантирует скрытие даже при возникновении ошибки.
Для маршрутов с параметрами важно корректно управлять индикатором при каждой загрузке. Например:
router.on('/users/:id', async (params) => {
showLoader();
try {
const response = await fetch(`/api/users/${params.id}`);
const user = await response.json();
renderUserProfile(user);
} catch (error) {
renderError(error);
} finally {
hideLoader();
}
});
Использование params позволяет подгружать данные
конкретного ресурса и синхронизировать отображение индикатора с
асинхронным процессом.
Для крупных приложений часто требуется один глобальный индикатор
загрузки, который активируется при любом переходе между маршрутами.
Navigo предоставляет хуки для событий before и
after, что позволяет централизованно управлять
индикатором:
router.hooks({
before: (done, match) => {
showLoader();
done();
},
after: () => {
hideLoader();
}
});
Такой подход избавляет от необходимости дублировать вызовы
showLoader() и hideLoader() в каждом
обработчике маршрута.
Когда требуется выполнять несколько асинхронных запросов одновременно, индикатор должен оставаться активным до завершения всех операций:
router.on('/dashboard', async () => {
showLoader();
try {
const [users, stats] = await Promise.all([
fetch('/api/users').then(res => res.json()),
fetch('/api/stats').then(res => res.json())
]);
renderDashboard(users, stats);
} catch (error) {
renderError(error);
} finally {
hideLoader();
}
});
Использование Promise.all позволяет контролировать
индикатор до завершения всех необходимых запросов, предотвращая
преждевременное скрытие.
Для улучшения UX индикатор можно совмещать с CSS-анимациями или библиотеками спиннеров. Например:
#loader {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-weight: bold;
background: rgba(0, 0, 0, 0.7);
color: white;
padding: 1em 2em;
border-radius: 8px;
display: none;
}
Добавление плавного появления и исчезновения через
opacity или transition делает интерфейс более
отзывчивым и приятным визуально.
Для маршрутов с быстрыми ответами сервера может быть полезно задерживать отображение индикатора на несколько миллисекунд, чтобы избежать «мигания»:
let loaderTimeout;
function showLoaderDelayed() {
loaderTimeout = setTimeout(showLoader, 100);
}
function hideLoaderImmediate() {
clearTimeout(loaderTimeout);
hideLoader();
}
Этот подход особенно полезен при работе с локальными кэшированными данными, когда загрузка выполняется практически мгновенно, и индикатор отображать бессмысленно.
В современных SPA важно корректно обрабатывать случаи, когда
пользователь быстро переключается между маршрутами. Для этого используют
сигнал отмены AbortController:
router.on('/users', async () => {
const controller = new AbortController();
const signal = controller.signal;
showLoader();
try {
const response = await fetch('/api/users', { signal });
const users = await response.json();
renderUsers(users);
} catch (error) {
if (error.name !== 'AbortError') renderError(error);
} finally {
hideLoader();
}
return () => controller.abort();
});
Метод возвращает функцию отмены, которая вызывается Navigo при переходе на другой маршрут, предотвращая отображение устаревших данных и корректно скрывая индикатор.
Этот подход к организации индикаторов загрузки в Navigo обеспечивает плавный пользовательский опыт, предотвращает мигание интерфейса и централизует управление визуальной обратной связью для всех маршрутов.