History API
Манипуляция историей браузера без перезагрузки — фундамент SPA-роутинга.
Что это
Глобал window.history хранит стек переходов. Раньше можно было только back/forward/go. С HTML5 добавили pushState и replaceState + событие popstate — это и есть фундамент SPA-роутинга (React Router, Angular Router, Vue Router).
Базовое использование
// Переход без reload — пушим новую запись
history.pushState({ page: 'episode-1' }, '', '/podcast/ep-1');
// Заменить текущую без новой записи (для query params)
history.replaceState({}, '', '?filter=active');
// Назад/вперёд
history.back;
history.forward;
history.go(-2);
// Реакция на back/forward пользователя
window.addEventListener('popstate', (e) => {
// e.state — то что мы пушили
const route = location.pathname;
render(route);
});
// Базовый роутер
function navigate(path, state = {}) {
history.pushState(state, '', path);
render(path);
}
API
| Метод/свойство | Что |
|---|---|
history.pushState(state, title, url) |
Новая запись в стек |
history.replaceState(state, title, url) |
Замена текущей |
history.back/forward/go(n) |
Программные переходы |
history.length |
Размер стека |
history.state |
Текущий state-объект |
event popstate |
back/forward пользователя |
event hashchange |
Изменение #hash (legacy-роутинг) |
Поддержка
Все современные браузеры (HTML5+). Старая альтернатива — hash-роутинг (location.hash + hashchange).
Подводные камни
pushStateне вызываетpopstate— слушатель срабатывает только на back/forward пользователя. Свой роутер должен вручную рендерить послеpushState- URL должен быть в том же origin — иначе SecurityError
- Параметр
titleигнорируется большинством браузеров (поставь'') - При первой загрузке
popstateНЕ срабатывает — рендери поlocation.pathnameв init - На сервере нужен fallback на
index.htmlдля всех роутов (history mode requires server config), иначе F5 на/podcast/ep-1→ 404
Используется в bootcamp
- Podcast Player — SPA-роутинг между списком и страницей эпизода (
/episodes,/episode/:id) - AsyncRace — переключение между гаражом и winners-страницей через URL, чтобы можно было поделиться/обновить