fillParams
const regexCompileCache = Object.create(null)
function fillParams(path,params,routeMsg){
params = params || {}
try{
// Create a compiled object based on the path
const filler = regexCompileCache[path] || (regexCompileCache[path] = Regexp.compile(path))
// If a string is matched, the path match is compiled in the first place
if(typeof params.pathMatch === 'string') params[0] = params.pathMatch
return filler(params,{pretty:true})}catch(e){
if(process.env.NODE_ENV ! = ='production'){
warn(typeof params.pathMatch==='string'.`missing param for ${routeMsg}:${e.message}`)}return ' '
}finally{
delete params[0]}}Copy the code
path
resolvePath
function resolvePath(relative,base,append){
// Query the first character of the path
const firstChar = relative.charAt(0)
// Returns directly starting with /
if(firstChar=== '/') {return relative
}
// Start with search or hash and add base returns
if(firstChar === '? ' || firstChar === The '#') {return base + relative
}
// Store path at each level
const stack = base.split('/')
// If no additional path is required or the last base path is empty, the last base path is removed
if(! append || ! stack[stack.length -1]){
stack.pop()
}
// Remove the head/cut
const segments = relative.replace(/ ^ / / /.' ').split('/')
for(let i = 0; i < segments.length; i ++){
const segment = segments[i]
/ / /.. Indicates to jump to a directory
if(segment === '.. '){
stack.pop()
}else if(segment ! = ='. ') {// If no, the storage path
stack.push(segment)
}
}
// Always start with a /
if(stack[0]! = =' '){
stack.unshift(' ')}return stack.join('/')}Copy the code
parsePath
// Cut path => query/hash/path
function parsePath(path){
let hash = ' '
let query = ' '
const hashIndex = path.indexOf(The '#')
if(hashIndex >= 0){
hash = path.slice(hashIndex)
path = path.slice(0,hashIndex)
}
const queryIndex = path.indexOf('? ')
if(queryIndex >= 0){
query = path.slice(queryIndex + 1)
path = path.slice(0,queryIndex)
}
return {
path,
query,
hash
}
}
Copy the code
cleanPath
// Replace // => /
function cleanPath(path){
return path.replace(/\/\//g.'/')}Copy the code
query
parseQuery
// Parse the kv of query
function parseQuery(query){
const res = {}
// Remove the header? / # / &
query = query.trim().replace(/ ^ (\? # | | &) /.' ')
if(! query){return res
}
query.split('&').forEach(param= > {
const parts = param.replace(/\+/g.' ').split('=')
const key = decode(parts.shift())
const val = parts.length > 0 ? decode(parts.join('=')) :null
if(res[key] === undefied){
res[key] = val
}else if (Array.isArray(res[key])){
res[key].push(val)
}else{
res[key] = [res[key],val]
}
})
return res
}
Copy the code
resolveQuery
function resolveQuery(query,extraQuery,_parseQuery){
// Use custom or default query parsing
const parse = _parseQuery || parseQuery
let parsedQuery
/ / query
try{
parsedQuery = parse(query || ' ')}catch(e){ process.env.NODE_ENV ! = ='production' && warn(false,e.message)
parsedQuery = {}
}
// Extend to query
for(const key in extraQuery){
const value = extraQuery[key]
parsedQuery = Array.isArry(value) ? value.map(castQueryParamValue) : castQueryParamValue
}
return parsedQuery
}
// Returns either null or String objects
const castQueryParamValue = value= > (value== null || typeof value === 'object' ? value : String(value) )
Copy the code
stringifyQuery
// Merge query kv into a string
function stringifyQuery(obj){
const res = obj ? Object.keys(obj).map(key= > {
const val = obj[key]
if(val === undefined) {return ' '
}
if(val === null) {return encode(key)
}
if(Array.isArray(val)){
const result = []
val.forEach(val2= > {
if(val2 === undefined) {return
}
if(val2 === null){
result.push(encode(key))
}else{
result.push(encode(key) + '=' + encode(val2))
}
})
return result.join('&')}return encode(key) + '=' + encode(val)
}).filter(x= > x.length > 0).join('&') : null
}
Copy the code
resolve-components
flatten
const flatten = (arr) = > Array.prototype.concat.apply([],arr)
Copy the code
flatMapComponents
const flatMapComponents = (matched,fn) = > flatten(matched.map(m= > Object.keys(m.components).map(key= > fn(m.components[key],m.instances[key],m,key))))
Copy the code
isESModule
// Determine the ES6 Module
const hasSymbol = typeof Symbol= = ='function' && typeof Symbol.toStringTag === 'symbol'
const isESModule = (obj) = > obj.__esModule || (hasSymbol && obj[Symbol.toStringTag] === 'Module')
Copy the code
resolveAsyncComponents
function resolveAsyncComponents(matched){
return (to,from,next) = > {
let hasASync = false
let pending = 0
let error = null
// def component/instance /match Route object /key Component key
flatMapComponents(matched,(def,_,match,key) = > {
// If it is a function component and CID is not added, it is considered asynchronous
if(typeof def === 'function' && def.cid === undefined){
hasAsync = true
pending ++
const resolve = once(resolvedDef= > {
// For ES6 modules, obtain components through default
if(isESModule(resolvedDef)){
resolvedDef = resolvedDef.default
}
// Parse the component
def.resolved = typeof resolvedDef === 'function' ? resolvedDef : _Vue.extend(resolvedDef)
match.components[key] = resolvedDef
// If component parsing is complete, go to the next step
pending --
if(pending <= 0){
next()
}
})
const reject = once(reason= > {
const msg = `Failed to resolve async component ${key}:${reason}`process.env.NODE_ENV ! = ='production' && warn(false,msg)
if(! error){ error = isError(reason) ? reason :new Error(msg)
next(error)
}
})
let res
// Parse the component
try{
res = def(resolve,reject)
}catch(e){
reject(e)
}
if(typeof res.then === 'function'){
res.then(resolve,reject)
}else{
const comp = res.component
if(comp && typeof comp.then === 'function'){
comp.then(resolve,reject)
}
}
}
})
if(! hasAsync) next() } }Copy the code
route
// match /? At the end
const trailingSlashRE = / / /? $/
Copy the code
createRoute
function createRoute(record,location,redirectedFrom,router){
// Create a route object
const stringifyQuery = router && router.options.stringifyQuery
let query = location.query || {}
try{
query = clone(query)
}catch(e){}
const 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)
}
Copy the code
clone
/ / copy
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
}
}
Copy the code
START
const START = createRoute(null, {path:'/'})
Copy the code
formatMatch
// Recursively find the parent of the current route as a match object
function formatMatch(record){
const res = []
while(record){
res.unshift(record)
record = record.parent
}
return res
}
Copy the code
getFullPath
// Restore the current path based on the configured or default Query resolution
function getFullPath({path,query = {},hash = ' '},_stringifyQuery){
const stringify = _stringifyQuery || stringifyQuery
return (path || '/') + stringify(query) + hash
}
Copy the code
isSameRoute
// Determine whether two routing objects are equal
function isSameRoute(a,b,onlyPath){
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,' ') && (onlyPath || (a.hash === b.hash && isObjectEqual(a.query,b.equery)))
}else if(a.name && b.name){
return a.name === b.name && (onlyPath || (a.hash === b.hash && isObjectEqual(a.query,b.equery) && isObjectEqual(a.params,b.params)))
}else{
return false}}Copy the code
isObjectEqual
// Check whether two objects are equal
function isObjectEqual(a={},b={}){
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[bKey]
if(aVal === null || bVal === null) return aVal === bVal
if(tyoeof aVal === 'object' && typeof bVal === 'object') {return isObjectEqual(aVal,bVal)
}
return String(aVal) === String(bVal)
})
}
Copy the code
isIncludedRoute
// Check whether the route is included
function isIncludedRoute(current,target){
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,target){
for(const key in target){
if(! (keyin current)){
return false}}return true
}
Copy the code
handleRouteEntered
function handleRouteEntered(route){
// Get the parent of the current route
for(let i = 0; i < route.matched.length; i ++){
const record = route.matched[i]
for(const name in record.instances){
// Get the vue instance and enterCbs callback that matches the route
const instance = record.instanced[name]
const cbs = record.enterCbs[name]
if(! instance || ! cbs)continue
// By default, the vue instance callback is cleared
delete record.enterCbs[name]
// Perform the Enter callback accordingly
for(let i = 0; i < cbs.length; i++){
if(! instance._isBeingDestroyed) cbs[i](instance) } } } }Copy the code