diff --git a/src/create-matcher.js b/src/create-matcher.js index fcb8a8092..e7d308c7d 100644 --- a/src/create-matcher.js +++ b/src/create-matcher.js @@ -12,6 +12,7 @@ import { decode } from './util/query' export type Matcher = { match: (raw: RawLocation, current?: Route, redirectedFrom?: Location) => Route; addRoutes: (routes: Array) => void; + addRoute: (parentNameOrRoute: string | RouteConfig, route?: RouteConfig) => void; }; export function createMatcher ( @@ -24,6 +25,12 @@ export function createMatcher ( createRouteMap(routes, pathList, pathMap, nameMap) } + function addRoute (parentOrRoute, route) { + const parent = (typeof parentOrRoute !== 'object') ? nameMap[parentOrRoute] : undefined + // $flow-disable-line + createRouteMap([route || parentOrRoute], pathList, pathMap, nameMap, parent) + } + function match ( raw: RawLocation, currentRoute?: Route, @@ -167,6 +174,7 @@ export function createMatcher ( return { match, + addRoute, addRoutes } } diff --git a/src/create-route-map.js b/src/create-route-map.js index 01c0836d2..8d74bcd60 100644 --- a/src/create-route-map.js +++ b/src/create-route-map.js @@ -8,7 +8,8 @@ export function createRouteMap ( routes: Array, oldPathList?: Array, oldPathMap?: Dictionary, - oldNameMap?: Dictionary + oldNameMap?: Dictionary, + parentRoute?: RouteRecord ): { pathList: Array, pathMap: Dictionary, @@ -22,7 +23,7 @@ export function createRouteMap ( const nameMap: Dictionary = oldNameMap || Object.create(null) routes.forEach(route => { - addRouteRecord(pathList, pathMap, nameMap, route) + addRouteRecord(pathList, pathMap, nameMap, route, parentRoute) }) // ensure wildcard routes are always at the end diff --git a/src/index.js b/src/index.js index 3eda7f778..bc6a27585 100644 --- a/src/index.js +++ b/src/index.js @@ -244,6 +244,13 @@ export default class VueRouter { } } + addRoute (parentOrRoute: string | RouteConfig, route?: RouteConfig) { + this.matcher.addRoute(parentOrRoute, route) + if (this.history.current !== START) { + this.history.transitionTo(this.history.getCurrentLocation()) + } + } + addRoutes (routes: Array) { this.matcher.addRoutes(routes) if (this.history.current !== START) { diff --git a/test/unit/specs/create-matcher.spec.js b/test/unit/specs/create-matcher.spec.js index b6d79e5ae..e2caacd76 100644 --- a/test/unit/specs/create-matcher.spec.js +++ b/test/unit/specs/create-matcher.spec.js @@ -22,6 +22,38 @@ describe('Creating Matcher', function () { process.env.NODE_ENV = 'production' }) + it('can add nested routes', function () { + const component = { name: 'fake' } + const matcher = createMatcher([ + { + path: '/p', + name: 'parent', + children: [ + { path: 'a', name: 'a', component }, + { + path: 'c', + name: 'child', + component, + children: [{ path: 'n', name: 'nested', component }] + } + ] + }, + { + // easier to debug tests + path: '*', name: 'not-found', component + } + ]) + + matcher.addRoute({ path: '/b', name: 'b', component }) + matcher.addRoute('parent', { path: 'b', name: 'p-b', component }) + matcher.addRoute('child', { path: 'b', name: 'p-c-b', component }) + + expect(matcher.match('/b').name).toBe('b') + expect(matcher.match('/p/b').name).toBe('p-b') + expect(matcher.match('/p/c/b').name).toBe('p-c-b') + expect(matcher.match('/p/c/n').name).toBe('nested') + }) + it('in development, has logged a warning if a named route does not exist', function () { process.env.NODE_ENV = 'development' const { name, matched } = match({ name: 'bar' }, routes[0])