-
-
Notifications
You must be signed in to change notification settings - Fork 5k
/
Copy pathapp.js
209 lines (191 loc) · 5.47 KB
/
app.js
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
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
const Home = { template: '<div>home</div>' }
const Foo = { template: '<div>foo</div>' }
const Bar = { template: '<div>bar</div>' }
/**
* Signatre of all route guards:
* @param {Route} to
* @param {Route} from
* @param {Function} next
*
* See http://router.vuejs.org/en/advanced/navigation-guards.html
* for more details.
*/
function guardRoute (to, from, next) {
if (window.confirm(`Navigate to ${to.path}?`)) {
next()
} else if (window.confirm(`Redirect to /baz?`)) {
next('/baz')
} else {
next(false)
}
}
// Baz implements an in-component beforeRouteLeave hook
const Baz = {
data () {
return { saved: false }
},
template: `
<div>
<p>baz ({{ saved ? 'saved' : 'not saved' }})</p>
<button @click="saved = true">save</button>
</div>
`,
beforeRouteLeave (to, from, next) {
if (this.saved || window.confirm('Not saved, are you sure you want to navigate away?')) {
next()
} else {
next(false)
}
}
}
// Qux implements an in-component beforeRouteEnter hook
const Qux = {
data () {
return {
msg: null
}
},
template: `<div>{{ msg }}</div>`,
beforeRouteEnter (to, from, next) {
// Note that enter hooks do not have access to `this`
// because it is called before the component is even created.
// However, we can provide a callback to `next` which will
// receive the vm instance when the route has been confirmed.
//
// simulate an async data fetch.
// this pattern is useful when you want to stay at current route
// and only switch after the data has been fetched.
setTimeout(() => {
next(vm => {
vm.msg = 'Qux'
})
}, 300)
}
}
// Quux implements an in-component beforeRouteUpdate hook.
// this hook is called when the component is reused, but the route is updated.
// For example, when navigating from /quux/1 to /quux/2.
const Quux = {
data () {
return {
prevId: 0
}
},
template: `<div>id:{{ $route.params.id }} prevId:{{ prevId }}</div>`,
beforeRouteUpdate (to, from, next) {
this.prevId = from.params.id
next()
}
}
// Nested implements an in-component beforeRouteUpdate hook that uses
// next(vm => {})
const Nested = {
data () {
return {
calls: 0,
updates: 0
}
},
template: `
<div>
<p>
nested calls:{{ calls }} updates:{{ updates }}
</p>
<router-view></router-view>
</div>
`,
beforeRouteUpdate (to, from, next) {
// calls is incremented every time anything navigates, even if the
// navigation is canceled by a child component.
this.calls++
next(vm => {
// updates is only incremented once all children confirm and complete
// navigation. If any children load data async, then this will not be
// called until all children have called next() themselves. If any child
// cancels navigation, then this will never be called.
vm.updates++
})
}
}
// Buux implements a cancelable beforeRouteUpdate hook
const Buux = {
data () {
return {
prevId: 0
}
},
template: `<div>buux id:{{ $route.params.id }} prevId:{{ prevId }}</div>`,
beforeRouteUpdate (to, from, next) {
if (window.confirm(`Navigate to ${to.path}?`)) {
next(vm => {
vm.prevId = from.params.id
})
} else {
next(false)
}
}
}
const router = new VueRouter({
mode: 'history',
base: __dirname,
routes: [
{ path: '/', component: Home },
// inline guard
{ path: '/foo', component: Foo, beforeEnter: guardRoute },
// using meta properties on the route config
// and check them in a global before hook
{ path: '/bar', component: Bar, meta: { needGuard: true }},
// Baz implements an in-component beforeRouteLeave hook
{ path: '/baz', component: Baz },
// Qux implements an in-component beforeRouteEnter hook
{ path: '/qux', component: Qux },
// in-component beforeRouteEnter hook for async components
{ path: '/qux-async', component: resolve => {
setTimeout(() => {
resolve(Qux)
}, 0)
} },
// in-component beforeRouteUpdate hook
{ path: '/quux/:id', component: Quux },
{ path: '/nested', component: Nested,
children: [
{ path: '', component: Home },
{ path: 'qux', component: Qux },
{ path: 'buux/:id', component: Buux }
]
}
]
})
router.beforeEach((to, from, next) => {
if (to.matched.some(m => m.meta.needGuard)) {
guardRoute(to, from, next)
} else {
next()
}
})
new Vue({
router,
template: `
<div id="app">
<h1>Navigation Guards</h1>
<ul>
<li><router-link to="/">/</router-link></li>
<li><router-link to="/foo">/foo</router-link></li>
<li><router-link to="/bar">/bar</router-link></li>
<li><router-link to="/baz">/baz</router-link></li>
<li><router-link to="/qux">/qux</router-link></li>
<li><router-link to="/qux-async">/qux-async</router-link></li>
<li><router-link to="/quux/1">/quux/1</router-link></li>
<li><router-link to="/quux/2">/quux/2</router-link></li>
<li><router-link to="/nested">/nested</router-link></li>
<li><router-link to="/nested/qux">/nested/qux</router-link></li>
<li><router-link to="/nested/buux/1">/nested/buux/1</router-link></li>
<li><router-link to="/nested/buux/2">/nested/buux/2</router-link></li>
</ul>
<router-view class="view"></router-view>
</div>
`
}).$mount('#app')