Skip to content

Commit 02c7e07

Browse files
committed
adjust navigation guard signature
1 parent b2fae05 commit 02c7e07

File tree

5 files changed

+64
-37
lines changed

5 files changed

+64
-37
lines changed

examples/auth-flow/app.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ import About from './components/About.vue'
99
import Dashboard from './components/Dashboard.vue'
1010
import Login from './components/Login.vue'
1111

12-
function requireAuth (route, redirect, next) {
12+
function requireAuth (to, from, next) {
1313
if (!auth.loggedIn()) {
14-
redirect({
14+
next({
1515
path: '/login',
16-
query: { redirect: route.fullPath }
16+
query: { redirect: to.fullPath }
1717
})
1818
} else {
1919
next()
@@ -28,9 +28,9 @@ const router = new VueRouter({
2828
{ path: '/dashboard', component: Dashboard, beforeEnter: requireAuth },
2929
{ path: '/login', component: Login },
3030
{ path: '/logout',
31-
beforeEnter (route, redirect) {
31+
beforeEnter (to, from, next) {
3232
auth.logout()
33-
redirect('/')
33+
next('/')
3434
}
3535
}
3636
]

examples/navigation-guards/app.js

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,17 @@ const Bar = { template: '<div>bar</div>' }
1010
/**
1111
* Signatre of all route guards:
1212
* @param {Route} route
13-
* @param {Function} redirect - redirect to another route
14-
* @param {Function} next - confirm the route
13+
* @param {Function} next - confirm the navigation
14+
* @param {Function} redirect - cancel and redirect to another route
15+
* @param {Function} abort - abort the navigation
1516
*/
16-
function guardRoute (route, redirect, next) {
17-
if (window.confirm(`Navigate to ${route.path}?`)) {
17+
function guardRoute (to, from, next) {
18+
if (window.confirm(`Navigate to ${to.path}?`)) {
1819
next()
1920
} else if (window.confirm(`Redirect to /baz?`)) {
20-
redirect('/baz')
21+
next('/baz')
22+
} else {
23+
next(false)
2124
}
2225
}
2326

@@ -32,9 +35,11 @@ const Baz = {
3235
<button @click="saved = true">save</button>
3336
</div>
3437
`,
35-
beforeRouteLeave (route, redirect, next) {
38+
beforeRouteLeave (to, from, next) {
3639
if (this.saved || window.confirm('Not saved, are you sure you want to navigate away?')) {
3740
next()
41+
} else {
42+
next(false)
3843
}
3944
}
4045
}
@@ -47,7 +52,7 @@ const Qux = {
4752
}
4853
},
4954
template: `<div>{{ msg }}</div>`,
50-
beforeRouteEnter (route, redirect, next) {
55+
beforeRouteEnter (to, from, next) {
5156
// Note that enter hooks do not have access to `this`
5257
// because it is called before the component is even created.
5358
// However, we can provide a callback to `next` which will
@@ -92,9 +97,9 @@ const router = new VueRouter({
9297
]
9398
})
9499

95-
router.beforeEach((route, redirect, next) => {
96-
if (route.matched.some(m => m.meta.needGuard)) {
97-
guardRoute(route, redirect, next)
100+
router.beforeEach((to, from, next) => {
101+
if (to.matched.some(m => m.meta.needGuard)) {
102+
guardRoute(to, from, next)
98103
} else {
99104
next()
100105
}

src/history/base.js

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import type VueRouter from '../index'
44
import { warn } from '../util/warn'
55
import { inBrowser } from '../util/dom'
66
import { runQueue } from '../util/async'
7-
import { createRoute, isSameRoute } from '../util/route'
7+
import { START, isSameRoute } from '../util/route'
88

99
export class History {
1010
router: VueRouter;
@@ -23,9 +23,7 @@ export class History {
2323
this.router = router
2424
this.base = normalizeBase(base)
2525
// start with a route object that stands for "nowhere"
26-
this.current = createRoute(null, {
27-
path: '__vue_router_init__'
28-
})
26+
this.current = START
2927
this.pending = null
3028
}
3129

@@ -43,7 +41,8 @@ export class History {
4341
}
4442

4543
confirmTransition (route: Route, cb: Function) {
46-
if (isSameRoute(route, this.current)) {
44+
const current = this.current
45+
if (isSameRoute(route, current)) {
4746
this.ensureURL()
4847
return
4948
}
@@ -65,15 +64,28 @@ export class History {
6564
)
6665

6766
this.pending = route
68-
const redirect = location => this.push(location)
69-
const iterator = (hook, next) => hook(route, redirect, next)
67+
const iterator = (hook, next) => {
68+
if (this.pending !== route) return
69+
hook(route, current, (to: any) => {
70+
if (to === false) {
71+
// next(false) -> abort navigation, ensure current URL
72+
this.ensureURL()
73+
} else if (typeof to === 'string' || typeof to === 'object') {
74+
// next('/') or next({ path: '/' }) -> redirect
75+
this.push(to)
76+
} else {
77+
// confirm transition and pass on the value
78+
next(to)
79+
}
80+
})
81+
}
7082

7183
runQueue(queue, iterator, () => {
7284
const postEnterCbs = []
7385
// wait until async components are resolved before
7486
// extracting in-component enter guards
7587
runQueue(extractEnterGuards(activated, postEnterCbs), iterator, () => {
76-
if (isSameRoute(route, this.pending)) {
88+
if (this.pending === route) {
7789
this.pending = null
7890
cb(route)
7991
this.router.app.$nextTick(() => {
@@ -146,12 +158,14 @@ function extractEnterGuards (matched: Array<RouteRecord>, cbs: Array<Function>):
146158
return flatMapComponents(matched, (def, _, match, key) => {
147159
const guard = def && def.beforeRouteEnter
148160
if (guard) {
149-
return function routeEnterGuard (route, redirect, next) {
150-
return guard(route, redirect, cb => {
151-
next()
152-
cb && cbs.push(() => {
153-
cb(match.instances[key])
154-
})
161+
return function routeEnterGuard (to, from, next) {
162+
return guard(to, from, cb => {
163+
next(cb)
164+
if (typeof cb === 'function') {
165+
cbs.push(() => {
166+
cb(match.instances[key])
167+
})
168+
}
155169
})
156170
}
157171
}
@@ -166,14 +180,15 @@ function resolveAsyncComponents (matched: Array<RouteRecord>): Array<?Function>
166180
// we want to halt the navigation until the incoming component has been
167181
// resolved.
168182
if (typeof def === 'function' && !def.options) {
169-
return (route, redirect, next) => {
183+
return (to, from, next) => {
170184
const resolve = resolvedDef => {
171185
match.components[key] = resolvedDef
172186
next()
173187
}
174188

175189
const reject = reason => {
176190
warn(false, `Failed to resolve async component ${key}: ${reason}`)
191+
next(false)
177192
}
178193

179194
const res = def(resolve, reject)

src/util/route.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ export function createRoute (
2323
return Object.freeze(route)
2424
}
2525

26+
// the starting route that represents the initial state
27+
export const START = createRoute(null, {
28+
path: '/'
29+
})
30+
2631
function formatMatch (record: ?RouteRecord): Array<RouteRecord> {
2732
const res = []
2833
while (record) {
@@ -38,7 +43,9 @@ function getFullPath ({ path, query = {}, hash = '' }) {
3843

3944
const trailingSlashRE = /\/$/
4045
export function isSameRoute (a: Route, b: ?Route): boolean {
41-
if (!b) {
46+
if (b === START) {
47+
return a === b
48+
} else if (!b) {
4249
return false
4350
} else if (a.path && b.path) {
4451
return (

test/e2e/specs/navigation-guards.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,9 @@ module.exports = {
7777
.dismissAlert()
7878
.waitFor(100)
7979
.dismissAlert()
80-
// url works
81-
.assert.urlEquals('http://localhost:8080/navigation-guards/foo')
82-
// but should not render anything
80+
// should redirect to root
81+
.assert.urlEquals('http://localhost:8080/navigation-guards/')
82+
// and should not render anything
8383
.assert.elementNotPresent('.view')
8484

8585
.url('http://localhost:8080/navigation-guards/foo')
@@ -91,9 +91,9 @@ module.exports = {
9191
.dismissAlert()
9292
.waitFor(100)
9393
.dismissAlert()
94-
// url works
95-
.assert.urlEquals('http://localhost:8080/navigation-guards/bar')
96-
// but should not render anything
94+
// should redirect to root
95+
.assert.urlEquals('http://localhost:8080/navigation-guards/')
96+
// and should not render anything
9797
.assert.elementNotPresent('.view')
9898

9999
.url('http://localhost:8080/navigation-guards/bar')

0 commit comments

Comments
 (0)