1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
|
# Сторожевые хуки
Как следует из названия, сторожевые хуки `Vue-router` используются для редиректов или отмены навигационных переходов. Есть несколько способов внедрить сторожевой хук: глобально, для конкретного пути, или для конкретного компонента.
Следует помнить, что **изменение параметров маршрута не вызывает выполнения сторожевых хуков enter/leave**. Вы можете добавить [watch на объект `$route`](../essentials/dynamic-matching.md#отслеживание-изменений-параметров) для отслеживания этих изменений, или использовать хук `beforeRouteUpdate`.
### Глобальные хуки
Глобальный хук можно зарегистрировать через `router.beforeEach`:
``` js
const router = new VueRouter({ ... })
router.beforeEach((to, from, next) => {
// ...
})
```
Глобальные сторожевые хуки вызываются в порядке создания при каждом навигационном переходе. Допускается асинхронное разрешение хуков — в этом случае переход считается **незавершённым** до тех пор, пока не будут разрешены все хуки.
В каждый сторожевой хук передаётся три параметра:
- **`to: Route`**: целевой [объект Route](../api/route-object.md), к которому осуществляется переход.
- **`from: Route`**: текущий путь, с которого осуществляется переход к новому.
- **`next: Function`**: функция, вызов которой **разрешает** хук. В зависимости от переданных в `next` аргументов, результатом будет:
- **`next()`**: переход к следующему хуку в цепочке. Если хуков больше нет, переход считается **подтверждённым**.
- **`next(false)`**: отмена перехода. Если URL был изменён (вручную пользователем, или кнопкой "назад"), он будет сброшен на соответствующий пути `from`.
- **`next('/')` или `next({ path: '/' })`**: перенаправление на другой путь. Текущий переход будет отменён, и процесс начнётся заново для нового пути. Вы можете передать любой объект местоположения в `next`, который позволяет вам указывать опции такие как `replace: true`, `name: 'home'` и любой другой параметр используемый во [входном параметре `to` компонента `router-link`](../api/router-link.md) или [`router.push`](../api/router-instance.md#methods)
- **`next(error)`**: (добавлено в версии 2.4.0+) если аргумент, переданный `next` является экземпляром `Error`, навигация будет прервана и ошибка будет передана в коллбек, зарегистрированный через [`router.onError()`](../api/router-instance.html#методы).
**Удостоверьтесь, что функция `next` так или иначе будет вызвана, иначе хук никогда не будет разрешён.**
### Глобальные хуки разрешения перехода
> Добавлено в версии 2.5.0
В 2.5.0+ вы можете зарегистрировать глобальный хук с помощью `router.beforeResolve`. Это похоже на `router.beforeEach`, с той разницей, что разрешающий хук будет вызван непосредственно перед подтверждением навигации, **после того, как будут разрешены все хуки компонента и асинхронные компоненты для маршрута**.
### Глобальные хуки завершения перехода
Можно также зарегистрировать глобальные хуки, вызываемые после завершения перехода. Однако, в отличие от сторожевых хуков, в них не передаётся функция `next`, и на ход перехода они повлиять не могут:
``` js
router.afterEach((to, from) => {
// ...
})
```
### Указание хука для конкретного пути
Сторожевые хуки `beforeEnter` можно указать напрямую для конкретного пути в его конфигурации:
``` js
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
// ...
}
}
]
})
```
Эти хуки ничем не отличаются от глобальных.
### Указание хука для конкретного компонента
Наконец, сторожевой хук можно указать и непосредственно в компоненте (том, что указан в конфигурации пути), используя следующие опции:
- `beforeRouteEnter`
- `beforeRouteUpdate` (добавлено в версии 2.2+)
- `beforeRouteLeave`
``` js
const Foo = {
template: `...`,
beforeRouteEnter (to, from, next) {
// вызывается до подтверждения пути, соответствующего этому компоненту.
// НЕ имеет доступа к контексту экземпляра компонента `this`,
// так как к моменту вызова экземпляр ещё не создан!
},
beforeRouteUpdate (to, from, next) {
// вызывается когда маршрут, что рендерит этот компонент изменился,
// но этот компонент будет повторно использован в новом маршруте.
// Например, для маршрута с динамическими параметрами `/foo/:id`, когда мы
// перемещаемся между `/foo/1` и `/foo/2`, экземпляр того же компонента `Foo`
// будет использован повторно, и этот хук будет вызван когда это случится.
// Также имеется доступ в `this` к экземпляру компонента.
},
beforeRouteLeave (to, from, next) {
// вызывается перед переходом от пути, соответствующего текущему компоненту;
// имеет доступ к контексту экземпляра компонента `this`.
}
}
```
Хук `beforeRouteEnter` **НЕ** имеет доступа к `this`, так как к моменту его вызова навигация ещё не подтверждена, а значит и экземпляр компонента ещё не создан.
Тем не менее, доступ к экземпляру можно получить, передав коллбэк в `next`. Эта функция будет вызвана после подтверждения навигации, а экземпляр компонента будет передан в неё в качестве параметра:
``` js
beforeRouteEnter (to, from, next) {
next(vm => {
// экземпляр компонента доступен как `vm`
})
}
```
Обратите внимание, что `beforeRouteEnter` — единственный хук, который поддерживает передачу коллбэка в `next`. Для `beforeRouteUpdate` и `beforeRouteLeave`, `this` уже доступен, поэтому передача коллбэка не требуется и поэтому *не поддерживается*:
```js
beforeRouteUpdate (to, from, next) {
// просто используйте `this`
this.name = to.params.name
next()
}
```
**Сторожевой хук ухода со страницы** обычно используется для предотвращения случайного ухода пользователя со страницы с несохранёнными изменениями. Навигацию можно отменить вызовом `next(false)`.
```js
beforeRouteLeave (to, from , next) {
const answer = window.confirm('Вы действительно хотите уйти? У вас есть несохранённые изменения!')
if (answer) {
next()
} else {
next(false)
}
}
```
### Полная цепочка обработки навигации
1. Срабатывание навигации.
2. Вызов leave-хуков в деактивируемых компонентах.
3. Вызов глобальных `beforeEach` хуков.
4. Вызов `beforeRouteUpdate` хука в переиспользуемых компонентах (2.2+).
5. Вызов `beforeEnter` в конфигурации маршрута.
6. Разрешение асинхронных компонентов для маршрута.
7. Вызов `beforeRouteEnter` в активируемых компонентах.
8. Вызов глобальных `beforeResolve` хуков (2.5+).
9. Навигация подтверждена.
10. Вызов глобальных `afterEach` хуков.
11. Выполняется обновление DOM.
12. Вызов коллбэков, переданных в `next` в `beforeRouteEnter` хуке с созданными экземплярами.
|