Skip to content

Commit fb32ccb

Browse files
committed
support in-component route hooks in global mixin
1 parent a5554a8 commit fb32ccb

File tree

3 files changed

+72
-29
lines changed

3 files changed

+72
-29
lines changed

src/components/link.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import { cleanPath } from '../util/path'
44
import { createRoute, isSameRoute, isIncludedRoute } from '../util/route'
55
import { normalizeLocation } from '../util/location'
6+
import { _Vue } from '../install'
67

78
// work around weird flow bug
89
const toTypes: Array<Function> = [String, Object]
@@ -71,7 +72,7 @@ export default {
7172
if (a) {
7273
// in case the <a> is a static node
7374
a.isStatic = false
74-
const extend = this.constructor.super.util.extend
75+
const extend = _Vue.util.extend
7576
const aData = a.data = extend({}, a.data)
7677
aData.on = on
7778
const aAttrs = a.data.attrs = extend({}, a.data.attrs)

src/history/base.js

Lines changed: 62 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { warn } from '../util/warn'
55
import { inBrowser } from '../util/dom'
66
import { runQueue } from '../util/async'
77
import { START, isSameRoute } from '../util/route'
8+
import { _Vue } from '../install'
89

910
export class History {
1011
router: VueRouter;
@@ -147,53 +148,82 @@ function resolveQueue (
147148
}
148149
}
149150

150-
function extractGuard (def, key) {
151-
if (typeof def === 'function' && def.options) {
152-
return def.options[key]
153-
} else if (def) {
154-
return def[key]
151+
function extractGuard (
152+
def: Object | Function,
153+
key: string
154+
): NavigationGuard | Array<NavigationGuard> {
155+
if (typeof def !== 'function') {
156+
// extend now so that global mixins are applied.
157+
def = _Vue.extend(def)
155158
}
159+
return def.options[key]
156160
}
157161

158162
function extractLeaveGuards (matched: Array<RouteRecord>): Array<?Function> {
159-
return flatMapComponents(matched, (def, instance) => {
163+
return flatten(flatMapComponents(matched, (def, instance) => {
160164
const guard = extractGuard(def, 'beforeRouteLeave')
161165
if (guard) {
162-
return function routeLeaveGuard () {
163-
return guard.apply(instance, arguments)
164-
}
166+
return Array.isArray(guard)
167+
? guard.map(guard => wrapLeaveGuard(guard, instance))
168+
: wrapLeaveGuard(guard, instance)
165169
}
166-
}).reverse()
170+
}).reverse())
171+
}
172+
173+
function wrapLeaveGuard (
174+
guard: NavigationGuard,
175+
instance: _Vue
176+
): NavigationGuard {
177+
return function routeLeaveGuard () {
178+
return guard.apply(instance, arguments)
179+
}
167180
}
168181

169182
function extractEnterGuards (
170183
matched: Array<RouteRecord>,
171184
cbs: Array<Function>,
172185
isValid: () => boolean
173186
): Array<?Function> {
174-
return flatMapComponents(matched, (def, _, match, key) => {
187+
return flatten(flatMapComponents(matched, (def, _, match, key) => {
175188
const guard = extractGuard(def, 'beforeRouteEnter')
176189
if (guard) {
177-
return function routeEnterGuard (to, from, next) {
178-
return guard(to, from, cb => {
179-
next(cb)
180-
if (typeof cb === 'function') {
181-
cbs.push(() => {
182-
// #750
183-
// if a router-view is wrapped with an out-in transition,
184-
// the instance may not have been registered at this time.
185-
// we will need to poll for registration until current route
186-
// is no longer valid.
187-
poll(cb, match.instances, key, isValid)
188-
})
189-
}
190+
return Array.isArray(guard)
191+
? guard.map(guard => wrapEnterGuard(guard, cbs, match, key, isValid))
192+
: wrapEnterGuard(guard, cbs, match, key, isValid)
193+
}
194+
}))
195+
}
196+
197+
function wrapEnterGuard (
198+
guard: NavigationGuard,
199+
cbs: Array<Function>,
200+
match: RouteRecord,
201+
key: string,
202+
isValid: () => boolean
203+
): NavigationGuard {
204+
return function routeEnterGuard (to, from, next) {
205+
return guard(to, from, cb => {
206+
next(cb)
207+
if (typeof cb === 'function') {
208+
cbs.push(() => {
209+
// #750
210+
// if a router-view is wrapped with an out-in transition,
211+
// the instance may not have been registered at this time.
212+
// we will need to poll for registration until current route
213+
// is no longer valid.
214+
poll(cb, match.instances, key, isValid)
190215
})
191216
}
192-
}
193-
})
217+
})
218+
}
194219
}
195220

196-
function poll (cb, instances, key, isValid) {
221+
function poll (
222+
cb: any, // somehow flow cannot infer this is a function
223+
instances: Object,
224+
key: string,
225+
isValid: () => boolean
226+
) {
197227
if (instances[key]) {
198228
cb(instances[key])
199229
} else if (isValid()) {
@@ -235,11 +265,15 @@ function flatMapComponents (
235265
matched: Array<RouteRecord>,
236266
fn: Function
237267
): Array<?Function> {
238-
return Array.prototype.concat.apply([], matched.map(m => {
268+
return flatten(matched.map(m => {
239269
return Object.keys(m.components).map(key => fn(
240270
m.components[key],
241271
m.instances[key],
242272
m, key
243273
))
244274
}))
245275
}
276+
277+
function flatten (arr) {
278+
return Array.prototype.concat.apply([], arr)
279+
}

src/install.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
import View from './components/view'
22
import Link from './components/link'
33

4+
export let _Vue
5+
46
export function install (Vue) {
57
if (install.installed) return
68
install.installed = true
79

10+
_Vue = Vue
11+
812
Object.defineProperty(Vue.prototype, '$router', {
913
get () { return this.$root._router }
1014
})
@@ -25,4 +29,8 @@ export function install (Vue) {
2529

2630
Vue.component('router-view', View)
2731
Vue.component('router-link', Link)
32+
33+
const strats = Vue.config.optionMergeStrategies
34+
// use the same hook merging strategy for route hooks
35+
strats.beforeRouteEnter = strats.beforeRouteLeave = strats.created
2836
}

0 commit comments

Comments
 (0)