File: navigation-guards.md

package info (click to toggle)
vue-router.js 3.4.9%2Bds-2
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 3,212 kB
  • sloc: javascript: 7,982; sh: 22; makefile: 5
file content (153 lines) | stat: -rw-r--r-- 8,638 bytes parent folder | download | duplicates (3)
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
# ナビゲーションガード

この名前が示すように、 `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/route-object.md)。
  
  - **`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.md)または [`router.push`](../api/router-instance.md#methods)で使用される任意のオプションを指定することができます。

  - **`next(error)`**: (2.4.0+) `next` に渡された引数が `Error` インスタンスである場合、ナビゲーションは中止され、エラーは `router.onError()` を介して登録されたコールバックに渡されます。

  **常に `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. 非アクティブ化されたコンポーネントで leave ガードを呼ぶ
3. グローバル `beforeEach` ガードを呼ぶ
4. 再利用されるコンポーネントで `beforeRouteUpdate` ガードを呼ぶ (2.2 以降)
5. ルート設定内の `beforeEnter` を呼ぶ
6. 非同期ルートコンポーネントを解決する
7. アクティブ化されたコンポーネントで `beforeRouteEnter` を呼ぶ
8. グローバル `beforeResolve` ガードを呼ぶ (2.5 以降)
9. ナビゲーションが確定される
10. グローバル `afterEach` フックを呼ぶ
11. DOM 更新がトリガされる
12. インスタンス化されたインスンタンスによって `beforeRouteEnter` ガードで `next` に渡されたコールバックを呼ぶ