API навигации
Экспериментально: Это экспериментальная технология.
Перед использованием в продуктовой среде внимательно изучите таблицу совместимости с браузерами.
API навигации предоставляет возможность инициировать, перехватывать и управлять действиями навигации браузера. Также он позволяет просматривать записи истории приложения. Это преемник предыдущих функций веб-платформы, таких как API истории и window.location, который решает их недостатки и специально разработан для нужд приложений с одностраничным интерфейсом (SPA).
Концепции и использование
В приложениях SPA шаблон страницы, как правило, остается неизменным во время использования, а содержимое динамически переписывается по мере перехода пользователя к различным страницам или функциям. В результате в браузере загружается только одна отдельная страница, что нарушает ожидаемое поведение пользователя при навигации вперёд и назад между различными позициями в истории просмотра. Эту проблему можно частично решить с помощью API истории, но он не предназначен для нужд SPA. API навигации призван восполнить этот пробел.
К API можно получить доступ через свойство Window.navigation, которое возвращает ссылку на глобальный объект Navigation. Каждый объект window имеет свой соответствующий экземпляр navigation.
Обработка навигации
Интерфейс navigation имеет несколько связанных событий, наиболее важным из которых является событие navigate. Оно срабатывает при инициировании любого типа навигации, что означает, что вы можете управлять всей навигацией по страницам из одного центрального места, что идеально подходит для функциональности маршрутизации в рамках SPA-фреймворков. (Это не так с API истории, где иногда трудно определить, как реагировать на все навигации.) Обработчик события navigate получает объект NavigateEvent, содержащий подробную информацию, в том числе данные о пункте назначения навигации, типе, наличии данных формы POST или запроса загрузки, и многое другое.
Объект NavigationEvent также предоставляет два метода:
-
intercept()принимает в качестве аргумента функцию обратного вызова, возвращающую промис. Это позволяет контролировать, что происходит при инициировании навигации. Например, в случае SPA это можно использовать для загрузки соответствующего нового содержимого в пользовательский интерфейс на основе пути URL, к которому осуществляется переход. -
scroll()позволяет вручную инициировать поведение прокрутки браузера (например, до фрагмента идентификатора в URL), если это имеет смысл для вашего кода, а не ожидать, что браузер обработает это автоматически.
После того, как навигация инициирована, и ваш обработчик intercept() вызван, создаётся экземпляр объекта NavigationTransition (доступный через Navigation.transition), который можно использовать для отслеживания процесса текущей навигации.
Примечание: В данном контексте «переход» относится к переходу между одной записью истории и другой. Он не связан с CSS-переходами.
Примечание: Вы также можете вызвать preventDefault(), чтобы полностью остановить навигацию для большинства типов навигации preventDefault(); отмена навигации по переходам пока не реализована.
Когда промис функции обработчика intercept() выполнится, событие navigatesuccess объекта Navigation сработает, позволяя выполнить код очистки после успешного завершения навигации. Если он отклонится, означая, что навигация не удалась, вместо этого сработает navigateerror, позволяя вам элегантно обработать случай неудачи. Также существует свойство finished объекта NavigationTransition, которое выполняется или отклоняется одновременно с срабатыванием вышеупомянутых событий, предоставляя ещё один способ обработки успешных и неудачных случаев.
Примечание: До появления API навигации для выполнения подобных действий вам пришлось бы прослушивать все события щелчков по ссылкам, выполнять e.preventDefault(), выполнять соответствующий вызов History.pushState(), а затем настраивать отображение страницы на основе нового URL. И это не обрабатывало бы все навигации — только инициированные пользователем щелчки по ссылкам.
Программное обновление и навигация по истории навигации
По мере навигации пользователя по вашему приложению каждый новый посещаемый пункт приводит к созданию записи в истории навигации. Каждая запись истории представлена отдельным экземпляром объекта NavigationHistoryEntry. Они содержат несколько свойств, таких как ключ записи, URL и информация о состоянии. Вы можете получить запись, на которой пользователь находится в данный момент, используя Navigation.currentEntry, и массив всех существующих записей истории с помощью Navigation.entries(). Каждый объект NavigationHistoryEntry имеет событие dispose, которое срабатывает, когда запись больше не является частью истории браузера. Например, если пользователь три раза переходит назад, а затем переходит вперёд куда-то ещё, эти три записи истории будут удалены.
Примечание: API навигации отображает только записи истории, созданные в текущем контексте просмотра, которые имеют тот же источник, что и текущая страница (например, не навигации внутри вложенных <iframe> или навигации между источниками), предоставляя точный список всех предыдущих записей истории только для вашего приложения. Это делает навигацию по истории гораздо менее хрупкой по сравнению со старым API истории.
Объект Navigation содержит все методы, необходимые для обновления и навигации по истории навигации:
-
Переходит по новому URL, создавая новую запись в истории навигации.
-
reload()Экспериментально -
Перезагружает текущую запись истории навигации.
-
back()Экспериментально -
Переходит к предыдущей записи истории навигации, если это возможно.
-
forward()Экспериментально -
Переходит к следующей записи истории навигации, если это возможно.
-
traverseTo()Экспериментально -
Переходит к конкретной записи истории навигации, определяемой по её значению ключа, которое получено через свойство
NavigationHistoryEntry.keyсоответствующей записи.
Каждый из вышеперечисленных методов возвращает объект, содержащий два промиса — { committed, finished }. Это позволяет вызывающей функции ожидать выполнения дальнейших действий до:
-
committedвыполняется, что означает, что видимый URL изменился и был создан новыйNavigationHistoryEntry. -
finishedвыполняется, что означает, что все промисы, возвращённые вашим обработчикомintercept(), выполнены. Это эквивалентно выполнению промисаNavigationTransition.finishedпри срабатывании событияnavigatesuccess, как упоминалось ранее. - любой из вышеперечисленных промисов отклоняется, что означает, что навигация не удалась по какой-либо причине.
Состояние
API навигации позволяет хранить состояние в каждой записи истории. Эта информация определяется разработчиком — она может быть любой. Например, вы можете хранить свойство visitCount, которое записывает количество посещений представления, или объект, содержащий несколько свойств, связанных с состоянием пользовательского интерфейса, чтобы состояние можно было восстановить, когда пользователь возвращается к этому представлению.
Чтобы получить состояние NavigationHistoryEntry, вы вызываете его метод getState(). Изначально он undefined, но когда информация о состоянии устанавливается в записи, он вернёт ранее установленное состояние.
Установка состояния немного сложнее. Вы не можете извлечь значение состояния и затем обновить его напрямую — копия, хранящаяся в записи, не изменится. Вместо этого вы обновляете его при выполнении navigate() или reload() — каждый из них необязательно принимает параметр объекта опций, который включает свойство state, содержащее новое состояние для установки в записи истории. Когда эти переходы завершаются, изменение состояния автоматически применяется.
В некоторых случаях изменение состояния будет независимым от навигации или перезагрузки — например, когда страница содержит элемент <details> (развернуть/свернуть). В этом случае вы можете сохранить состояние раскрытия/свертывания в записи истории, чтобы восстановить его, когда пользователь возвращается на страницу или перезапускает браузер. Такие случаи обрабатываются с помощью Navigation.updateCurrentEntry(). currententrychange сработает, когда изменение текущей записи будет завершено.
Ограничения
Существует несколько предполагаемых ограничений API навигации:
- Текущая спецификация не вызывает событие
navigateпри первой загрузке страницы. Это может подойти для сайтов, использующих предварительную рендеризацию на стороне сервера (SSR) — ваш сервер может вернуть правильное начальное состояние, что является самым быстрым способом отображения контента пользователям. Но сайты, использующие клиентский код для создания страниц, могут потребовать дополнительную функцию для инициализации страницы. - API навигации работает только в пределах одного фрейма — главной страницы или одного конкретного
<iframe>. Это имеет некоторые интересные последствия, которые документированы в спецификации, но на практике это уменьшит путаницу у разработчиков. Предыдущий API истории History API имеет несколько запутанных особых случаев, таких как поддержка фреймов, которые API навигации обрабатывает заранее. - В настоящее время вы не можете использовать API навигации для программированного изменения или перестановки списка истории. Это может быть полезно для временного состояния, например, перенаправления пользователя на временный модальный диалог, который запрашивает у него информацию, а затем возвращает к предыдущему URL. В этом случае вы захотите удалить запись временного модального диалога в истории навигации, чтобы пользователь не мог нарушить поток приложения, нажав кнопку «вперед» и снова открыв его.
Интерфейсы
-
Объект события для события
navigate, которое срабатывает при инициировании любого типа навигации любого типа навигации. Он предоставляет доступ к информации об этой навигации, и, прежде всего, кintercept(), что позволяет вам контролировать то, что происходит при инициировании навигации. -
Позволяет управлять всеми действиями навигации для текущего
windowв одном централизованном месте, включая инициирование навигации программно, изучение записей истории навигации и управление навигацией во время ее выполнения. -
Представляет недавнюю навигацию между документами. Она содержит тип навигации и текущие и целевые записи истории документов.
-
Объект события для события
currententrychange, которое срабатывает при измененииNavigation.currentEntry. Он предоставляет доступ к типу навигации и предыдущей записи истории, из которой происходила навигация. -
Представляет конечную точку, к которой происходит навигация в текущей навигации.
-
Представляет отдельную запись истории навигации.
-
Представляет текущую навигацию.
Расширения других интерфейсов
-
Возвращает текущий объект
windowсвязанный объектNavigation. Это точка входа в API навигации.
Примеры
Примечание: Ознакомьтесь с живым демо API навигации Domenic Denicola.
Обработка навигации с помощью intercept()
navigation.addEventListener("navigate", (event) => {
// Exit early if this navigation shouldn't be intercepted,
// e.g. if the navigation is cross-origin, or a download request
if (shouldNotIntercept(event)) {
return;
}
const url = new URL(event.destination.url);
if (url.pathname.startsWith("/articles/")) {
event.intercept({
async handler() {
// The URL has already changed, so show a placeholder while
// fetching the new content, such as a spinner or loading page
renderArticlePagePlaceholder();
// Fetch the new content and display when ready
const articleContent = await getArticleContent(url.pathname);
renderArticlePage(articleContent);
},
});
}
});
Обработка прокрутки с помощью scroll()
В этом примере перехвата навигации функция handler() начинает с извлечения и рендеринга контента статьи, а затем извлекает и отображает дополнительный контент. Логично прокрутить страницу к основному содержанию статьи как можно скорее, как только оно станет доступно, чтобы пользователь мог взаимодействовать с ним, а не ждать, пока будет отрисован и дополнительный контент. Для этого мы добавили вызов scroll() между двумя этапами.
navigation.addEventListener("navigate", (event) => {
if (shouldNotIntercept(event)) {
return;
}
const url = new URL(event.destination.url);
if (url.pathname.startsWith("/articles/")) {
event.intercept({
async handler() {
const articleContent = await getArticleContent(url.pathname);
renderArticlePage(articleContent);
event.scroll();
const secondaryContent = await getSecondaryContent(url.pathname);
addSecondaryContent(secondaryContent);
},
});
}
});
Переход к определённой записи истории
// On JS startup, get the key of the first loaded page
// so the user can always go back there.
const { key } = navigation.currentEntry;
backToHomeButton.onclick = () => navigation.traverseTo(key);
// Navigate away, but the button will always work.
await navigation.navigate("/another_url").finished;
Обновление состояния
navigation.navigate(url, { state: newState });
Или
navigation.reload({ state: newState });
Или, если изменение состояния независимо от навигации или перезагрузки:
navigation.updateCurrentEntry({ state: newState });
Спецификации
| Спецификация |
|---|
| HTML # navigation-api |
Совместимость с браузерами
| Рабочие столы | Мобильные устройства | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
| Chrome | Edge | Firefox | Opera | Safari | Chrome Android | Firefox для Android | Opera Android | Safari на iOS | Samsung Internet | WebView Android | |
Navigation_API |
102 | 102 | Нет | 88 | Нет | 102 | Нет | 70 | Нет | 19.0 | 102 |
finished |
102 | 102 | Нет | 88 | Нет | 102 | Нет | 70 | Нет | 19.0 | 102 |
from |
102 | 102 | Нет | 88 | Нет | 102 | Нет | 70 | Нет | 19.0 | 102 |
navigationType |
102 | 102 | Нет | 88 | Нет | 102 | Нет | 70 | Нет | 19.0 | 102 |
| Рабочий стол | Мобильный | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
| Chrome | Edge | Firefox | Opera | Safari | Chrome Android | Firefox для Android | Opera Android | Safari на IOS | Samsung Internet | WebView Android | |
Navigation_API |
102 | 102 | Нет | 88 | Нет | 102 | Нет | 70 | Нет | 19.0 | 102 |
dispose_event |
102 | 102 | Нет | 88 | Нет | 102 | Нет | 70 | Нет | 19.0 | 102 |
getState |
102 | 102 | Нет | 88 | Нет | 102 | Нет | 70 | Нет | 19.0 | 102 |
id |
102 | 102 | Нет | 88 | Нет | 102 | Нет | 70 | Нет | 19.0 | 102 |
index |
102 | 102 | Нет | 88 | Нет | 102 | Нет | 70 | Нет | 19.0 | 102 |
key |
102 | 102 | Нет | 88 | Нет | 102 | Нет | 70 | Нет | 19.0 | 102 |
sameDocument |
102 | 102 | Нет | 88 | Нет | 102 | Нет | 70 | Нет | 19.0 | 102 |
url |
102 | 102 | Нет | 88 | Нет | 102 | Нет | 70 | Нет | 19.0 | 102 |
| Рабочий стол | Мобильный | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
| Chrome | Edge | Firefox | Opera | Safari | Chrome Android | Firefox для Android | Opera Android | Safari на IOS | Samsung Internet | WebView Android | |
Navigation_API |
102 | 102 | Нет | 88 | Нет | 102 | Нет | 70 | Нет | 19.0 | 102 |
getState |
102 | 102 | Нет | 88 | Нет | 102 | Нет | 70 | Нет | 19.0 | 102 |
id |
102 | 102 | Нет | 88 | Нет | 102 | Нет | 70 | Нет | 19.0 | 102 |
index |
102 | 102 | Нет | 88 | Нет | 102 | Нет | 70 | Нет | 19.0 | 102 |
key |
102 | 102 | Нет | 88 | Нет | 102 | Нет | 70 | Нет | 19.0 | 102 |
sameDocument |
102 | 102 | Нет | 88 | Нет | 102 | Нет | 70 | Нет | 19.0 | 102 |
url |
102 | 102 | Нет | 88 | Нет | 102 | Нет | 70 | Нет | 19.0 | 102 |
| Настольный компьютер | Мобильный | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
| Chrome | Edge | Firefox | Opera | Safari | Chrome Android | Firefox for Android | Opera Android | Safari на IOS | Samsung Internet | WebView Android | |
Navigation_API |
102 | 102 | No | 88 | No | 102 | No | 70 | No | 19.0 | 102 |
activation |
123 | 123 | No | 109 | No | 123 | No | 82 | No | 27.0 | 123 |
back |
102 | 102 | No | 88 | No | 102 | No | 70 | No | 19.0 | 102 |
canGoBack |
102 | 102 | No | 88 | No | 102 | No | 70 | No | 19.0 | 102 |
canGoForward |
102 | 102 | No | 88 | No | 102 | No | 70 | No | 19.0 | 102 |
currentEntry |
102 | 102 | No | 88 | No | 102 | No | 70 | No | 19.0 | 102 |
currententrychange_event |
102 | 102 | No | 88 | No | 102 | No | 70 | No | 19.0 | 102 |
entries |
102 | 102 | No | 88 | No | 102 | No | 70 | No | 19.0 | 102 |
forward |
102 | 102 | No | 88 | No | 102 | No | 70 | No | 19.0 | 102 |
navigate |
102 | 102 | No | 88 | No | 102 | No | 70 | No | 19.0 | 102 |
navigate_event |
102 | 102 | No | 88 | No | 102 | No | 70 | No | 19.0 | 102 |
navigateerror_event |
102 | 102 | No | 88 | No | 102 | No | 70 | No | 19.0 | 102 |
navigatesuccess_event |
102 | 102 | No | 88 | No | 102 | No | 70 | No | 19.0 | 102 |
reload |
102 | 102 | No | 88 | No | 102 | No | 70 | No | 19.0 | 102 |
transition |
102 | 102 | No | 88 | No | 102 | No | 70 | No | 19.0 | 102 |
traverseTo |
102 | 102 | No | 88 | No | 102 | No | 70 | No | 19.0 | 102 |
updateCurrentEntry |
102 | 102 | No | 88 | No | 102 | No | 70 | No | 19.0 | 102 |
api.Navigation
Таблицы BCD загружаются только в браузере
api.NavigationDestination
Таблицы BCD загружаются только в браузере
api.NavigationHistoryEntry
Таблицы BCD загружаются только в браузере
api.NavigationTransition
Таблицы BCD загружаются только в браузере
См. также
© 2005–2024 MDN contributors.
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
https://developer.mozilla.org/en-US/docs/Web/API/Navigation_API