返回

VueRouter源码解析——深入理解fillParams、path、resolvePath等方法

前端







## 导读

在本文中,我们将深入分析VueRouter的源代码,详细了解fillParams、path、resolvePath、parsePath、cleanPath、query、parseQuery、resolveQuery、stringifyQuery和resolve方法的实现细节,以便更深入地理解VueRouter的工作原理。

## fillParams方法

fillParams方法用于将动态参数填充到路径模板中。例如,对于路径模板`/user/:id`,如果动态参数为`123`,那么fillParams方法将返回`/user/123`。

```js
const fillParams = (path, params, routeConfig) => {
  for (const key in params) {
    const value = params[key]
    const segment = routeConfig.pathSegments.find(segment => segment.param === key)
    if (segment) {
      path = path.replace(segment.regex, value)
    }
  }
  return path
}

path方法

path方法用于获取当前路由的路径。

const path = () => {
  return currentRoute.fullPath || '/'
}

resolvePath方法

resolvePath方法用于解析路径。它会将路径中的动态参数替换为对应的值。例如,对于路径/user/:id,如果动态参数为123,那么resolvePath方法将返回/user/123

const resolvePath = (relative, current, append) => {
  if (relative.charAt(0) === '/') {
    return relative
  }

  if (relative.charAt(0) === '?' || relative.charAt(0) === '#') {
    return current + relative
  }

  const stack = current.split('/')
  // remove trailing slash
  stack.pop()
  // resolve relative path
  const segments = relative.replace(/^\//, '').split('/')
  for (let i = 0; i < segments.length; i++) {
    const segment = segments[i]
    if (segment === '.') {
      continue
    } else if (segment === '..') {
      stack.pop()
    } else {
      stack.push(segment)
    }
  }
  // ensure leading slash
  if (stack[0] !== '') {
    stack.unshift('')
  }
  return stack.join('/')
}

parsePath方法

parsePath方法用于解析路径。它会将路径分解为一个对象,其中包含路径的各个部分。例如,对于路径/user/123,parsePath方法将返回一个对象:

{
  path: '/user/123',
  params: { id: '123' }
}
const parsePath = (path) => {
  const hash = path.indexOf('#')
  if (hash >= 0) {
    path = path.slice(0, hash)
  }

  const query = path.indexOf('?')
  if (query >= 0) {
    path = path.slice(0, query)
  }

  return {
    path,
    query,
    hash
  }
}

cleanPath方法

cleanPath方法用于清除路径中的多余部分。例如,对于路径/user///123///,cleanPath方法将返回/user/123

const cleanPath = (path) => {
  return path.replace(/\/\//g, '/')
}

query方法

query方法用于获取当前路由的查询参数。

const query = () => {
  return currentRoute.query || {}
}

parseQuery方法

parseQuery方法用于解析查询参数。它会将查询参数分解为一个对象。例如,对于查询参数id=123,parseQuery方法将返回一个对象:

{
  id: '123'
}
const parseQuery = (query) => {
  const result = {}
  query = query.trim().replace(/^(\?|#|&)/, '')
  if (!query) {
    return result
  }

  query.split('&').forEach(param => {
    const parts = param.replace(/\+/g, ' ').split('=')
    const key = decodeURIComponent(parts.shift())
    const val = parts.length > 0 ? decodeURIComponent(parts.join('=')) : null

    if (key in result) {
      result[key] = [].concat(result[key], val)
    } else {
      result[key] = val
    }
  })

  return result
}

resolveQuery方法

resolveQuery方法用于解析查询参数。它会将查询参数中的动态参数替换为对应的值。例如,对于查询参数id=:id,如果动态参数为123,那么resolveQuery方法将返回一个对象:

{
  id: '123'
}
const resolveQuery = (query, current, routeConfig) => {
  if (!query || !routeConfig) {
    return query
  }

  const queryParams = parseQuery(query)
  const dynamicParams = {}

  for (const key in queryParams) {
    const value = queryParams[key]
    const segment = routeConfig.pathSegments.find(segment => segment.param === key)
    if (segment) {
      dynamicParams[key] = value
    }
  }

  return stringifyQuery(dynamicParams, query)
}

stringifyQuery方法

stringifyQuery方法用于将查询参数转换为字符串。

const stringifyQuery = (obj) => {
  const query = []
  for (const key in obj) {
    const value = obj[key]
    if (value == null) {
      continue
    }

    if (Array.isArray(value)) {
      for (let i = 0; i < value.length; i++) {
        query.push(encodeURIComponent(key) + '=' + encodeURIComponent(value[i]))
      }
    } else {
      query.push(encodeURIComponent(key) + '=' + encodeURIComponent(value))
    }
  }

  return query.join('&')
}

resolve方法

resolve方法用于解析路径和查询参数。它会将路径和查询参数中的动态参数替换为对应的值。例如,对于路径/user/:id和查询参数id=:id,如果动态参数为123,那么resolve方法将返回一个对象:

{
  path: '/user/123',
  query: { id: '123' }
}
const resolve = (path, current, append) => {
  let parsedPath
  let parsedQuery

  if (typeof path === 'string') {
    parsedPath = parsePath(path)
  } else {
    parsedPath = path
  }

  parsedQuery = parseQuery(parsedPath.query)

  const routeConfig = findRoute(parsedPath.path, current)

  if (!routeConfig) {
    return createRoute(null, parsedPath, parsedQuery)
  }

  const resolvedPath = resolvePath(parsedPath.path, current, append)
  const resolvedQuery = resolveQuery(parsedQuery, current, routeConfig)

  return createRoute(routeConfig, {
    path: resolvedPath,
    query: resolvedQuery
  })
}

总结

在本文中,我们详细分析了VueRouter的源代码,深入了解了fillParams、path、resolvePath、parsePath、cleanPath、query、parseQuery、resolveQuery、stringifyQuery和resolve方法的实现细节。这些方法对于理解VueRouter的工作原理非常重要。