123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151 |
- /* @flow */
- import type VueRouter from '../index'
- import { stringifyQuery } from './query'
- const trailingSlashRE = /\/?$/
- export function createRoute (
- record: ?RouteRecord,
- location: Location,
- redirectedFrom?: ?Location,
- router?: VueRouter
- ): Route {
- const stringifyQuery = router && router.options.stringifyQuery
- let query: any = location.query || {}
- try {
- query = clone(query)
- } catch (e) {}
- const route: Route = {
- name: location.name || (record && record.name),
- meta: (record && record.meta) || {},
- path: location.path || '/',
- hash: location.hash || '',
- query,
- params: location.params || {},
- fullPath: getFullPath(location, stringifyQuery),
- matched: record ? formatMatch(record) : []
- }
- if (redirectedFrom) {
- route.redirectedFrom = getFullPath(redirectedFrom, stringifyQuery)
- }
- return Object.freeze(route)
- }
- function clone (value) {
- if (Array.isArray(value)) {
- return value.map(clone)
- } else if (value && typeof value === 'object') {
- const res = {}
- for (const key in value) {
- res[key] = clone(value[key])
- }
- return res
- } else {
- return value
- }
- }
- // the starting route that represents the initial state
- export const START = createRoute(null, {
- path: '/'
- })
- function formatMatch (record: ?RouteRecord): Array<RouteRecord> {
- const res = []
- while (record) {
- res.unshift(record)
- record = record.parent
- }
- return res
- }
- function getFullPath (
- { path, query = {}, hash = '' },
- _stringifyQuery
- ): string {
- const stringify = _stringifyQuery || stringifyQuery
- return (path || '/') + stringify(query) + hash
- }
- export function isSameRoute (a: Route, b: ?Route): boolean {
- if (b === START) {
- return a === b
- } else if (!b) {
- return false
- } else if (a.path && b.path) {
- return (
- a.path.replace(trailingSlashRE, '') === b.path.replace(trailingSlashRE, '') &&
- a.hash === b.hash &&
- isObjectEqual(a.query, b.query)
- )
- } else if (a.name && b.name) {
- return (
- a.name === b.name &&
- a.hash === b.hash &&
- isObjectEqual(a.query, b.query) &&
- isObjectEqual(a.params, b.params)
- )
- } else {
- return false
- }
- }
- function isObjectEqual (a = {}, b = {}): boolean {
- // handle null value #1566
- if (!a || !b) return a === b
- const aKeys = Object.keys(a).sort()
- const bKeys = Object.keys(b).sort()
- if (aKeys.length !== bKeys.length) {
- return false
- }
- return aKeys.every((key, i) => {
- const aVal = a[key]
- const bKey = bKeys[i]
- if (bKey !== key) return false
- const bVal = b[key]
- // query values can be null and undefined
- if (aVal == null || bVal == null) return aVal === bVal
- // check nested equality
- if (typeof aVal === 'object' && typeof bVal === 'object') {
- return isObjectEqual(aVal, bVal)
- }
- return String(aVal) === String(bVal)
- })
- }
- export function isIncludedRoute (current: Route, target: Route): boolean {
- return (
- current.path.replace(trailingSlashRE, '/').indexOf(
- target.path.replace(trailingSlashRE, '/')
- ) === 0 &&
- (!target.hash || current.hash === target.hash) &&
- queryIncludes(current.query, target.query)
- )
- }
- function queryIncludes (current: Dictionary<string>, target: Dictionary<string>): boolean {
- for (const key in target) {
- if (!(key in current)) {
- return false
- }
- }
- return true
- }
- export function handleRouteEntered (route: Route) {
- for (let i = 0; i < route.matched.length; i++) {
- const record = route.matched[i]
- for (const name in record.instances) {
- const instance = record.instances[name]
- const cbs = record.enteredCbs[name]
- if (!instance || !cbs) continue
- delete record.enteredCbs[name]
- for (let i = 0; i < cbs.length; i++) {
- if (!instance._isBeingDestroyed) cbs[i](instance)
- }
- }
- }
- }
|