Защитники навигации
Как следует из названия, защитники навигации, предоставляемые Vue Router, в основном используются для защиты навигации, либо перенаправляя ее, либо отменяя. Существует несколько способов подключиться к процессу навигации по маршрутам: глобально, по маршруту или в компоненте.
Глобальные защитники до входа
Вы можете зарегистрировать глобальные защитники до входа, используя router.beforeEach.
const router = createRouter({ ... })
router.beforeEach((to, from) => {
// ...
// explicitly return false to cancel the navigation
return false
})
Глобальные защитники до входа вызываются в порядке регистрации при каждом срабатывании навигации. Защитники могут быть разрешены асинхронно, и навигация считается ожидающей до тех пор, пока все хуки не будут разрешены.
Каждая функция защитника получает два аргумента:
-
to: целевой маршрут перехода в нормализованном формате. -
from: текущий маршрут перехода в нормализованном формате.
И может необязательно возвращать любое из следующих значений:
-
false: отменить текущую навигацию. Если адрес браузера был изменен (либо вручную пользователем, либо через кнопку "Назад"), он будет сброшен на адрес маршрутаfrom. - Объект Местоположения маршрута: перенаправить на другое местоположение, передав местоположение маршрута так, как будто вы вызываете
router.push(), что позволяет вам передавать параметры, такие какreplace: trueилиname: 'home'. Текущая навигация отменяется, и создается новая с тем жеfrom.
Также возможно бросить Error в случае непредвиденной ситуации. Это также отменит навигацию и вызовет любой зарегистрированный обратный вызов через router.onError().
Если ничего, undefined или true не возвращается, навигация проверяется, и вызывается следующий защитник навигации.
Всё вышеперечисленное действует аналогичным образом с функциями async и Promise:
router.beforeEach(async (to, from) => {
// canUserAccess() returns `true` or `false`
const canAccess = await canUserAccess(to)
if (!canAccess) return '/login'
})
Необязательный третий аргумент next
В предыдущих версиях Vue Router также было возможно использовать третий аргумент next, это был распространённый источник ошибок и был удалён по RFC . Однако он всё ещё поддерживается, что означает, что вы можете передать третий аргумент любому защитнику навигации. В этом случае, вы должны вызвать next ровно один раз в каждом проходе через защитник навигации. Он может появляться более одного раза, но только если логические пути не перекрываются, в противном случае хук никогда не будет разрешён или вызовет ошибки. Вот плохой пример перенаправления пользователя на /login в случае, если он не авторизован:
// BAD
router.beforeEach((to, from, next) => {
if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })
// if the user is not authenticated, `next` is called twice
next()
})
Вот правильная версия:
// GOOD
router.beforeEach((to, from, next) => {
if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })
else next()
})
Глобальные защитники разрешения
Вы можете зарегистрировать глобального защитника с router.beforeResolve. Это аналогично router.beforeEach, поскольку срабатывает при каждой навигации, но защитники разрешения вызываются непосредственно перед подтверждением навигации, после всех защитников внутри компонента и асинхронных компонентов маршрута. Вот пример, который гарантирует, что пользователь имеет доступ к камере для маршрутов, имеющих определённое пользовательское свойство meta requiresCamera.
router.beforeResolve(async to => {
if (to.meta.requiresCamera) {
try {
await askForCameraPermission()
} catch (error) {
if (error instanceof NotAllowedError) {
// ... handle the error and then cancel the navigation
return false
} else {
// unexpected error, cancel the navigation and pass the error to the global handler
throw error
}
}
}
})
router.beforeResolve — идеальное место для получения данных или выполнения других операций, которые вы хотите избежать, если пользователь не может перейти на страницу.
Глобальные хуки после
Вы также можете зарегистрировать глобальные хуки после, однако, в отличие от защитников, эти хуки не получают функцию next и не могут повлиять на навигацию:
router.afterEach((to, from) => {
sendToAnalytics(to.fullPath)
})
Они полезны для аналитики, изменения заголовка страницы, функций доступности, таких как объявление страницы, и многих других вещей.
Они также отражают ошибки навигации в качестве третьего аргумента:
router.afterEach((to, from, failure) => {
if (!failure) sendToAnalytics(to.fullPath)
})
Узнайте больше об ошибках навигации на своей странице руководства.
Защитник по маршруту
Вы можете определить защитники beforeEnter маршрутов непосредственно в объекте конфигурации маршрута:
const routes = [
{
path: '/users/:id',
component: UserDetails,
beforeEnter: (to, from) => {
// reject the navigation
return false
},
},
]
Защитники beforeEnter срабатывают только при входе в маршрут, они не срабатывают, когда params, query или hash изменяются, например, при переходе от /users/2 к /users/3 или от /users/2#info к /users/2#projects . Они срабатывают только при переходе с другого маршрута.
Вы также можете передать массив функций в beforeEnter, это полезно при повторном использовании защитников для разных маршрутов:
function removeQueryParams(to) {
if (Object.keys(to.query).length)
return { path: to.path, query: {}, hash: to.hash }
}
function removeHash(to) {
if (to.hash) return { path: to.path, query: to.query, hash: '' }
}
const routes = [
{
path: '/users/:id',
component: UserDetails,
beforeEnter: [removeQueryParams, removeHash],
},
{
path: '/about',
component: UserDetails,
beforeEnter: [removeQueryParams],
},
]
Обратите внимание, что аналогичного поведения можно достичь, используя поля метаданных маршрутов и глобальные защитники навигации.
Защитники внутри компонента
Использование API опций
Вы можете добавить следующие опции к компонентам маршрутов:
beforeRouteEnterbeforeRouteUpdatebeforeRouteLeave
const UserDetails = {
template: `...`,
beforeRouteEnter(to, from) {
// called before the route that renders this component is confirmed.
// does NOT have access to `this` component instance,
// because it has not been created yet when this guard is called!
},
beforeRouteUpdate(to, from) {
// called when the route that renders this component has changed,
// but this component is reused in the new route.
// For example, given a route with params `/users/:id`, when we
// navigate between `/users/1` and `/users/2`, the same `UserDetails` component instance
// will be reused, and this hook will be called when that happens.
// Because the component is mounted while this happens, the navigation guard has access to `this` component instance.
},
beforeRouteLeave(to, from) {
// called when the route that renders this component is about to
// be navigated away from.
// As with `beforeRouteUpdate`, it has access to `this` component instance.
},
}
Защитник beforeRouteEnter НЕ имеет доступа к this, потому что защитник вызывается до подтверждения навигации, а значит новый входящий компонент еще не создан.
Однако вы можете получить доступ к экземпляру, передав обратный вызов в next. Обратный вызов будет вызван, когда навигация будет подтверждена, и экземпляр компонента будет передан обратному вызову в качестве аргумента:
beforeRouteEnter (to, from, next) {
next(vm => {
// access to component public instance via `vm`
})
}
Обратите внимание, что beforeRouteEnter — единственный защитник, который поддерживает передачу обратного вызова в next. Для beforeRouteUpdate и beforeRouteLeave экземпляр this уже доступен, поэтому передача обратного вызова не требуется и, следовательно, не поддерживается:
beforeRouteUpdate (to, from) {
// just use `this`
this.name = to.params.name
}
Защитник выхода обычно используется для предотвращения случайного выхода из маршрута с незасохраненными изменениями. Навигацию можно отменить, вернув false.
beforeRouteLeave (to, from) {
const answer = window.confirm('Do you really want to leave? you have unsaved changes!')
if (!answer) return false
}
Использование композиционного API
Если вы пишете свой компонент, используя композиционный API и функцию setup, вы можете добавить защитники обновления и выхода через onBeforeRouteUpdate и onBeforeRouteLeave соответственно. Подробности см. в разделе Композиционный API.
Полный процесс разрешения навигации
- Срабатывает навигация.
- Вызываются защитники
beforeRouteLeaveв деактивированных компонентах. - Вызываются глобальные защитники
beforeEach. - Вызываются защитники
beforeRouteUpdateв повторно используемых компонентах. - Вызываются защитники
beforeEnterв конфигурациях маршрутов. - Разрешаются асинхронные компоненты маршрутов.
- Вызываются защитники
beforeRouteEnterв активированных компонентах. - Вызываются глобальные защитники
beforeResolve. - Навигация подтверждена.
- Вызываются глобальные хуки
afterEach. - Срабатывают обновления DOM.
- Вызываются обратные вызовы, переданные в
nextв защитникахbeforeRouteEnterс созданными экземплярами.
© 2013–present Evan You
Licensed under the MIT License.
https://next.router.vuejs.org/guide/advanced/navigation-guards