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 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
|
# ナビゲーションガード
<div class="vueschool"><a href="https://vueschool.io/courses/vue-router-for-everyone?friend=vuerouter" target="_blank" rel="sponsored noopener" title="Learn how to build powerful Single Page Applications with the Vue Router on Vue School">Watch a free video course about Vue Router on Vue School</a></div>
この名前が示すように、 `vue-router` によって提供されるナビゲーションガードは、リダイレクトもしくはキャンセルによって遷移をガードするために主に使用されます。ルートナビゲーション処理 (グローバル、ルート単位、コンポーネント内) をフックする多くの方法があります。
**パラメータまたはクエリの変更は enter/leave ナビゲーションガードをトリガーしない** ということを覚えておいてください。それらの変更に対応するために [`$route` オブジェクトを監視する](../essentials/dynamic-matching.md#reacting-to-params-changes)、またはコンポーネント内ガード `beforeRouteUpdate` を使用するかの、どちらかができます。
## グローバルビフォーガード
`router.beforeEach` を使ってグローバル before ガードを登録できます。
```js
const router = new VueRouter({ ... })
router.beforeEach((to, from, next) => {
// ...
})
```
いつナビゲーションがトリガーされようとも、グローバル before ガードは作られた順番で呼び出されます。ガードは非同期に解決されるかもしれません。そしてそのナビゲーションは全てのフックが解決されるまで **未解決状態** として扱われます。
全てのガード関数は 3 つの引数を受け取ります。
- **`to: Route`**: 次にナビゲーションされる対象の [ルートオブジェクト](../../api/#ルートオブジェクト)。
- **`from: Route`**: ナビゲーションされる前の現在のルートです。
- **`next: Function`**: フックを **解決** するためにこの関数を呼ぶ必要があります。この振る舞いは `next` に渡される引数に依存します:
- **`next()`**: パイプラインの次のフックに移動します。もしフックが残っていない場合は、このナビゲーションは **確立** されます。
- **`next(false)`**: 現在のナビゲーションを中止します。もしブラウザの URL が変化した場合は(ユーザーが手動で変更した場合でも、戻るボタンの場合でも)、 `from` ルートの URL にリセットされます。
- **`next('/')` または `next({ path: '/' })`**: 異なる場所へリダイレクトします。現在のナビゲーションは中止され、あたらしいナビゲーションが始まります。任意のロケーションオブジェクトを `next` に渡すことができます。この `next` には、`replace: true`、 `name: 'home'` のようなオプション、そして [`router-link`、`to` プロパティ](../../api/#router-link)または [`router.push`](../../api/#ルーターインスタンスプロパティ)で使用される任意のオプションを指定することができます。
- **`next(error)`**: (2.4.0+) `next` に渡された引数が `Error` インスタンスである場合、ナビゲーションは中止され、エラーは `router.onError()` を介して登録されたコールバックに渡されます。
**与えられたナビゲーションガードを通過する任意のパスにおいて、常に 1 回だけ `next` 関数が呼び出されるようにしてください。それは 1 回以上出現することがありますが、論理パスが重ならないときだけで、そうしないないとフックは決して解決されない、またはエラーが発生します。** 以下は、ユーザーが認証されていない場合、`/login` にリダレクトするための例です:
```js
// BAD
router.beforeEach((to, from, next) => {
if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })
// ユーザーが認証されていない場合、 `next` は2回呼ばれる
next()
})
```
```js
// GOOD
router.beforeEach((to, from, next) => {
if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })
else next()
})
```
## グローバル解決ガード
> New in 2.5.0
2.5.0 以降では、`router.beforeResolve` によってグローバルガードを登録できます。これは `router.beforeEach` に似ていますが、**すべてのコンポーネント内ガードと非同期ルートコンポーネントが解決された後**、ナビゲーションが解決される直前に解決ガードが呼び出されるという違いがあります。
## グローバルな After フック
グローバル after フックを登録することもできます。しかしながら、ガードとは異なり、これらのフックは `next` 関数を受け取らず、ナビゲーションに影響しません。
```js
router.afterEach((to, from) => {
// ...
})
```
## ルート単位ガード
直接ルート設定オブジェクトの `beforeEnter` ガードを定義することができます。
```js
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
// ...
}
}
]
})
```
これらのガードはグローバル before ガードと全く同じシグネチャを持ちます。
### コンポーネント内ガード
最後に、 以下のオプションでルートコンポーネント(ルータ設定に渡されるもの)の内側でルートナビゲーションガードを直接定義することができます。
- `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` を通じてコンポーネントインスタンスにアクセス
})
}
```
コールバックを `next` に渡すことをサポートするのは、`beforeRouteEnter` ガードだけであるということに注意してください。`beforeRouteUpdate` と `beforeRouteLeave` の場合、 `this` は既に利用可能です。したがって、コールバックを渡す必要はないので、_サポートされません_:
```js
beforeRouteUpdate (to, from, next) {
// `this` を使用
this.name = to.params.name
next()
}
```
**leave ガード**は、通常、ユーザが保存されていない編集内容で誤って経路を離れるのを防ぐために使用されます。ナビゲーションは `next(false)` を呼び出すことで取り消すことができます。
```js
beforeRouteLeave (to, from, next) {
const answer = window.confirm('Do you really want to leave? you have unsaved changes!')
if (answer) {
next()
} else {
next(false)
}
}
```
## 完全なナビゲーション解決フロー
1. ナビゲーションがトリガされる
2. 非アクティブ化されたコンポーネントで `beforeRouteLeave` ガードを呼ぶ
3. グローバル `beforeEach` ガードを呼ぶ
4. 再利用されるコンポーネントで `beforeRouteUpdate` ガードを呼ぶ (2.2 以降)
5. ルート設定内の `beforeEnter` を呼ぶ
6. 非同期ルートコンポーネントを解決する
7. アクティブ化されたコンポーネントで `beforeRouteEnter` を呼ぶ
8. グローバル `beforeResolve` ガードを呼ぶ (2.5 以降)
9. ナビゲーションが確定される
10. グローバル `afterEach` フックを呼ぶ
11. DOM 更新がトリガされる
12. インスタンス化されたインスンタンスによって `beforeRouteEnter` ガードで `next` に渡されたコールバックを呼ぶ
|