ナビゲーションガード
この名前が示すように、 vue-router
によって提供されるナビゲーションガードは、リダイレクトもしくはキャンセルによって遷移をガードするために主に使用されます。ルートナビゲーション処理 (グローバル、ルート単位、コンポーネント内) をフックする多くの方法があります。
パラメータまたはクエリの変更は enter/leave ナビゲーションガードをトリガーしない ということを覚えておいてください。それらの変更に対応するために $route
オブジェクトを監視する、またはコンポーネント内ガード beforeRouteUpdate
を使用するかの、どちらかができます。
グローバルビフォーガード
router.beforeEach
を使ってグローバル before ガードを登録できます。
const router = new VueRouter({ ... })
router.beforeEach((to, from, next) => {
// ...
})
いつナビゲーションがトリガーされようとも、グローバル before ガードは作られた順番で呼び出されます。ガードは非同期に解決されるかもしれません。そしてそのナビゲーションは全てのフックが解決されるまで 未解決状態 として扱われます。
全てのガード関数は 3 つの引数を受け取ります。
to: Route
: 次にナビゲーションされる対象の ルートオブジェクト。from: Route
: ナビゲーションされる前の現在のルートです。next: Function
: フックを 解決 するためにこの関数を呼ぶ必要があります。この振る舞いはnext
に渡される引数に依存します:next()
: パイプラインの次のフックに移動します。もしフックが残っていない場合は、このナビゲーションは 確立 されます。next(false)
: 現在のナビゲーションを中止します。もしブラウザのURLが変化した場合は(ユーザーが手動で変更した場合でも、戻るボタンの場合でも)、from
ルートのURLにリセットされます。next('/')
またはnext({ path: '/' })
: 異なる場所へリダイレクトします。現在のナビゲーションは中止され、あたらしいナビゲーションが始まります。任意のロケーションオブジェクトをnext
に渡すことができます。このnext
には、replace: true
、name: 'home'
のようなオプション、そしてrouter-link
、to
プロパティまたはrouter.push
で使用される任意のオプションを指定することができます。next(error)
: (2.4.0+)next
に渡された引数がError
インスタンスである場合、ナビゲーションは中止され、エラーはrouter.onError()
を介して登録されたコールバックに渡されます。
与えられたナビゲーションガードを通過する任意のパスにおいて、常に 1 回だけ next
関数が呼び出されるようにしてください。それは 1 回以上出現することがありますが、論理パスが重ならないときだけで、そうしないないとフックは決して解決されない、またはエラーが発生します。 以下は、ユーザーが認証されていない場合、/login
にリダレクトするための例です:
// BAD
router.beforeEach((to, from, next) => {
if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })
// ユーザーが認証されていない場合、 `next` は2回呼ばれる
next()
})
// 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
関数を受け取らず、ナビゲーションに影響しません。
router.afterEach((to, from) => {
// ...
})
ルート単位ガード
直接ルート設定オブジェクトの beforeEnter
ガードを定義することができます。
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
// ...
}
}
]
})
これらのガードはグローバル before ガードと全く同じシグネチャを持ちます。
コンポーネント内ガード
最後に、 以下のオプションでルートコンポーネント(ルータ設定に渡されるもの)の内側でルートナビゲーションガードを直接定義することができます。
beforeRouteEnter
beforeRouteUpdate
(2.2 で追加)beforeRouteLeave
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
にコールバックを渡すことでインスタンスにアクセスすることができます。このコールバックはナビゲーションが確立した時に呼ばれ、コンポーネントインスタンスはそのコールバックの引数として渡されます。
beforeRouteEnter (to, from, next) {
next(vm => {
// `vm` を通じてコンポーネントインスタンスにアクセス
})
}
コールバックを next
に渡すことをサポートするのは、beforeRouteEnter
ガードだけであるということに注意してください。beforeRouteUpdate
と beforeRouteLeave
の場合、 this
は既に利用可能です。したがって、コールバックを渡す必要はないので、サポートされません:
beforeRouteUpdate (to, from, next) {
// `this` を使用
this.name = to.params.name
next()
}
leave ガードは、通常、ユーザが保存されていない編集内容で誤って経路を離れるのを防ぐために使用されます。ナビゲーションは next(false)
を呼び出すことで取り消すことができます。
beforeRouteLeave (to, from, next) {
const answer = window.confirm('Do you really want to leave? you have unsaved changes!')
if (answer) {
next()
} else {
next(false)
}
}
完全なナビゲーション解決フロー
- ナビゲーションがトリガされる
- 非アクティブ化されたコンポーネントで
beforeRouteLeave
ガードを呼ぶ - グローバル
beforeEach
ガードを呼ぶ - 再利用されるコンポーネントで
beforeRouteUpdate
ガードを呼ぶ (2.2 以降) - ルート設定内の
beforeEnter
を呼ぶ - 非同期ルートコンポーネントを解決する
- アクティブ化されたコンポーネントで
beforeRouteEnter
を呼ぶ - グローバル
beforeResolve
ガードを呼ぶ (2.5 以降) - ナビゲーションが確定される
- グローバル
afterEach
フックを呼ぶ - DOM 更新がトリガされる
- インスタンス化されたインスンタンスによって
beforeRouteEnter
ガードでnext
に渡されたコールバックを呼ぶ