В Chrome 105 представлены два новых метода NavigateEvent
API навигации (представленные в версии 102) для улучшения методов, которые на практике оказались проблематичными. intercept()
, который позволяет разработчикам контролировать состояние после навигации, заменяет transitionWhile()
, который оказался трудным в использовании. Метод scroll()
, который выполняет прокрутку до привязки, указанной в URL-адресе, заменяет restoreScroll()
который работает не для всех типов навигации.
В этой статье я объясню проблемы обоих и то, как новые методы решают эти проблемы.
NavigateEvent.transitionWhile()
Метод NavigateEvent.trasitionWhile()
, представленный в API навигации в Chrome 102, перехватывает навигацию для переходов на стороне клиента в одностраничных приложениях. Его первый аргумент — это обещание, которое сигнализирует браузеру и другим частям веб-приложения о завершении работы.
На практике это работало плохо. Рассмотрим этот общий шаблон кодирования:
event.transitionWhile((async () => {
doSyncStuff();
await doAsyncStuff();
})());
Это функционально эквивалентно приведенному ниже коду. Это приводит к тому, что некоторая часть навигации запускается до того, как API узнает, что разработчик намеревается перехватить навигацию.
doSyncStuff();
event.transitionWhile((async () => {
await doAsyncStuff();
})());
Одним из примеров того, как это может испортить приложение, является логика восстановления прокрутки, когда оно фиксирует позиции прокрутки после изменения DOM, а не до него.
Что изменилось
Чтобы заменитьtransitionWhile transitionWhile()
, текущая спецификация вводит NavigateEvent.intercept()
. Новый метод принимает обработчик в дополнение к свойствам focusReset
и scrollRestoration
поддерживаемым transitionWhile()
. Новый обработчик всегда запускается после фиксации навигации и захвата таких вещей, как позиции прокрутки, что позволяет избежать проблем с transitionWhile()
.
transitionWhile()
по-прежнему доступен, но он устарел и будет удален в Chrome 108.
Использование перехвата()
NavigateEvent.intercept()
имеет те же ограничения, что transitionWhile()
, поскольку его нельзя вызывать для всех событий навигации. Навигацию между источниками нельзя перехватить, как и обход между документами. При этом возникнет исключение DOMException
типа "SecurityError"
.
Чтобы использовать intercept()
, просто передайте свой собственный обработчик при его вызове.
navigation.addEventListener("navigate", event => {
event.intercept({
async handler() {
doSyncStuff();
await doAsyncStuff();
}
});
});
NavigateEvent.scroll()
Навигация, например, от верхней части страницы к якорю (назовем это переходом от /a
к /a#id
), полностью обрабатывается браузером даже в одностраничном приложении. Но переход к привязке на другой «странице» ( /a
до /b#id
), что просто для многостраничных приложений, сложнее для одностраничных приложений. Приложение должно перехватить переход к /b#id
с помощью NavigateEvent.transitionWhile()
, а затем вызвать NavigateEvent.restoreScroll()
чтобы отобразить привязку. Как уже говорилось выше, в настоящее время это сделать сложно.
Что изменилось
В одностраничных приложениях теперь вы можете контролировать, обрабатывает ли браузер прокрутку до привязки или ваш код.
Использование прокрутки()
По умолчанию браузер попытается автоматически обработать прокрутку после выполнения обработчика перехвата. Если вы хотите управлять прокруткой самостоятельно, установите для scroll
значение "manual"
, а затем вызовите NavigateEvent.scroll()
, когда браузер попытается установить позицию прокрутки.
navigation.addEventListener("manual", event => {
scroll: "manual",
event.intercept({
async handler() {
doSyncStuff();
// Handle scrolling earlier than by default:
event.scroll();
await doAsyncStuff();
}
});
});
Метод restoreScroll()
по-прежнему доступен, но он устарел и будет удален в Chrome 108.
Заключение
Мы надеемся вскоре обновить нашу статью о API навигации. Между тем, спецификация этого API содержит много информации специально для веб-разработчиков.