Skip to content

Commit 2f97b19

Browse files
committed
support custom stringify/parse query
1 parent 5197c4e commit 2f97b19

File tree

10 files changed

+70
-18
lines changed

10 files changed

+70
-18
lines changed

flow/declarations.js

+2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ declare type RouterOptions = {
2020
mode?: string;
2121
base?: string;
2222
linkActiveClass?: string;
23+
parseQuery?: (query: string) => Object;
24+
stringifyQuery?: (query: Object) => string;
2325
scrollBehavior?: (
2426
to: Route,
2527
from: Route,

src/components/link.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,13 @@ export default {
3131
const router = this.$router
3232
const current = this.$route
3333
const { location, route, href } = router.resolve(this.to, current, this.append)
34+
3435
const classes = {}
3536
const activeClass = this.activeClass || router.options.linkActiveClass || 'router-link-active'
36-
const compareTarget = location.path ? createRoute(null, location) : route
37+
const compareTarget = location.path
38+
? createRoute(null, location, null, router)
39+
: route
40+
3741
classes[activeClass] = this.exact
3842
? isSameRoute(current, compareTarget)
3943
: isIncludedRoute(current, compareTarget)

src/create-matcher.js

+8-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/* @flow */
22

3+
import type VueRouter from './index'
34
import { assert, warn } from './util/warn'
45
import { createRoute } from './util/route'
56
import { createRouteMap } from './create-route-map'
@@ -12,7 +13,10 @@ export type Matcher = {
1213
addRoutes: (routes: Array<RouteConfig>) => void;
1314
};
1415

15-
export function createMatcher (routes: Array<RouteConfig>): Matcher {
16+
export function createMatcher (
17+
routes: Array<RouteConfig>,
18+
router: VueRouter
19+
): Matcher {
1620
const { pathMap, nameMap } = createRouteMap(routes)
1721

1822
function addRoutes (routes) {
@@ -24,7 +28,7 @@ export function createMatcher (routes: Array<RouteConfig>): Matcher {
2428
currentRoute?: Route,
2529
redirectedFrom?: Location
2630
): Route {
27-
const location = normalizeLocation(raw, currentRoute)
31+
const location = normalizeLocation(raw, currentRoute, false, router)
2832
const { name } = location
2933

3034
if (name) {
@@ -70,7 +74,7 @@ export function createMatcher (routes: Array<RouteConfig>): Matcher {
7074
): Route {
7175
const originalRedirect = record.redirect
7276
let redirect = typeof originalRedirect === 'function'
73-
? originalRedirect(createRoute(record, location))
77+
? originalRedirect(createRoute(record, location, null, router))
7478
: originalRedirect
7579

7680
if (typeof redirect === 'string') {
@@ -156,7 +160,7 @@ export function createMatcher (routes: Array<RouteConfig>): Matcher {
156160
if (record && record.matchAs) {
157161
return alias(record, location, record.matchAs)
158162
}
159-
return createRoute(record, location, redirectedFrom)
163+
return createRoute(record, location, redirectedFrom, router)
160164
}
161165

162166
return {

src/history/base.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
/* @flow */
22

3+
import { _Vue } from '../install'
34
import type Router from '../index'
45
import { warn } from '../util/warn'
56
import { inBrowser } from '../util/dom'
67
import { runQueue } from '../util/async'
78
import { START, isSameRoute } from '../util/route'
8-
import { _Vue } from '../install'
99

1010
export class History {
1111
router: Router;

src/index.js

+7-2
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ export default class VueRouter {
3737
this.options = options
3838
this.beforeHooks = []
3939
this.afterHooks = []
40-
this.matcher = createMatcher(options.routes || [])
40+
this.matcher = createMatcher(options.routes || [], this)
4141

4242
let mode = options.mode || 'hash'
4343
this.fallback = mode === 'history' && !supportsPushState
@@ -178,7 +178,12 @@ export default class VueRouter {
178178
normalizedTo: Location,
179179
resolved: Route
180180
} {
181-
const location = normalizeLocation(to, current || this.history.current, append)
181+
const location = normalizeLocation(
182+
to,
183+
current || this.history.current,
184+
append,
185+
this
186+
)
182187
const route = this.match(location, current)
183188
const fullPath = route.redirectedFrom || route.fullPath
184189
const base = this.history.base

src/util/location.js

+11-3
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
/* @flow */
22

3+
import type VueRouter from '../index'
34
import { parsePath, resolvePath } from './path'
45
import { resolveQuery } from './query'
56
import { fillParams } from './params'
67
import { warn } from './warn'
78

89
export function normalizeLocation (
910
raw: RawLocation,
10-
current?: Route,
11-
append?: boolean
11+
current: ?Route,
12+
append: ?boolean,
13+
router: ?VueRouter
1214
): Location {
1315
let next: Location = typeof raw === 'string' ? { path: raw } : raw
1416
// named target
@@ -38,7 +40,13 @@ export function normalizeLocation (
3840
const path = parsedPath.path
3941
? resolvePath(parsedPath.path, basePath, append || next.append)
4042
: (current && current.path) || '/'
41-
const query = resolveQuery(parsedPath.query, next.query)
43+
44+
const query = resolveQuery(
45+
parsedPath.query,
46+
next.query,
47+
router && router.options.parseQuery
48+
)
49+
4250
let hash = next.hash || parsedPath.hash
4351
if (hash && hash.charAt(0) !== '#') {
4452
hash = `#${hash}`

src/util/query.js

+4-2
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,13 @@ const decode = decodeURIComponent
1717

1818
export function resolveQuery (
1919
query: ?string,
20-
extraQuery: Dictionary<string> = {}
20+
extraQuery: Dictionary<string> = {},
21+
_parseQuery: ?Function
2122
): Dictionary<string> {
23+
const parse = _parseQuery || parseQuery
2224
let parsedQuery
2325
try {
24-
parsedQuery = parseQuery(query || '')
26+
parsedQuery = parse(query || '')
2527
} catch (e) {
2628
process.env.NODE_ENV !== 'production' && warn(false, e.message)
2729
parsedQuery = {}

src/util/route.js

+12-5
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,29 @@
11
/* @flow */
22

3+
import type VueRouter from '../index'
34
import { stringifyQuery } from './query'
45

56
const trailingSlashRE = /\/?$/
67

78
export function createRoute (
89
record: ?RouteRecord,
910
location: Location,
10-
redirectedFrom?: Location
11+
redirectedFrom?: ?Location,
12+
router?: VueRouter
1113
): Route {
14+
const stringifyQuery = router && router.options.stringifyQuery
1215
const route: Route = {
1316
name: location.name || (record && record.name),
1417
meta: (record && record.meta) || {},
1518
path: location.path || '/',
1619
hash: location.hash || '',
1720
query: location.query || {},
1821
params: location.params || {},
19-
fullPath: getFullPath(location),
22+
fullPath: getFullPath(location, stringifyQuery),
2023
matched: record ? formatMatch(record) : []
2124
}
2225
if (redirectedFrom) {
23-
route.redirectedFrom = getFullPath(redirectedFrom)
26+
route.redirectedFrom = getFullPath(redirectedFrom, stringifyQuery)
2427
}
2528
return Object.freeze(route)
2629
}
@@ -39,8 +42,12 @@ function formatMatch (record: ?RouteRecord): Array<RouteRecord> {
3942
return res
4043
}
4144

42-
function getFullPath ({ path, query = {}, hash = '' }) {
43-
return (path || '/') + stringifyQuery(query) + hash
45+
function getFullPath (
46+
{ path, query = {}, hash = '' },
47+
_stringifyQuery
48+
): string {
49+
const stringify = _stringifyQuery || stringifyQuery
50+
return (path || '/') + stringify(query) + hash
4451
}
4552

4653
export function isSameRoute (a: Route, b: ?Route): boolean {

test/unit/specs/custom-query.spec.js

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import Vue from 'vue'
2+
import VueRouter from '../../../src/index'
3+
4+
Vue.use(VueRouter)
5+
6+
describe('custom query parse/stringify', () => {
7+
it('should work', () => {
8+
const router = new VueRouter({
9+
parseQuery: () => ({ foo: 1 }),
10+
stringifyQuery: () => '?foo=1'
11+
})
12+
13+
router.push('/?bar=2')
14+
15+
expect(router.currentRoute.query).toEqual({ foo: 1 })
16+
expect(router.currentRoute.fullPath).toEqual('/?foo=1')
17+
})
18+
})

types/router.d.ts

+2
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ export interface RouterOptions {
4747
mode?: RouterMode;
4848
base?: string;
4949
linkActiveClass?: string;
50+
parseQuery?: (query: string) => Object;
51+
stringifyQuery?: (query: Object) => string;
5052
scrollBehavior?: (
5153
to: Route,
5254
from: Route,

0 commit comments

Comments
 (0)