Vue.js 源码分析:路由参数传递与 query 处理
【免费下载链接】vue-analysis :thumbsup: Vue.js 源码分析 项目地址: https://gitcode.com/gh_mirrors/vu/vue-analysis
在 Vue.js 应用开发中,路由参数传递是连接不同页面数据的核心机制。无论是动态路由参数(Params)还是查询字符串(Query),Vue-Router 都提供了灵活的处理方案。本文将从源码角度解析两种参数传递方式的实现原理,帮助开发者深入理解参数解析流程与最佳实践。
路由参数传递的两种方式
Vue-Router 支持两种主要参数传递方式,分别适用于不同场景:
1. 动态路由参数(Params)
使用场景:页面路径中表示资源唯一标识,如用户ID、商品编号等
实现方式:在路由配置中使用:参数名定义,通过$route.params访问
// 路由配置 [src/index.js](https://link.gitcode.com/i/ce6502334bdf2362b678c0d907da1a18)
const routes = [
{ path: '/user/:id', component: User }
]
// 跳转方式
<router-link to="/user/123">用户123</router-link>
// 或编程式导航
this.$router.push('/user/123')
// 组件中访问
this.$route.params.id // "123"
2. 查询字符串(Query)
使用场景:页面筛选条件、分页参数等非核心标识信息
实现方式:URL中?后的键值对,通过$route.query访问
// 跳转方式
<router-link to="/list?page=1&sort=desc">列表页</router-link>
// 或编程式导航
this.$router.push({ path: '/list', query: { page: 1, sort: 'desc' } })
// 组件中访问
this.$route.query.page // "1"
this.$route.query.sort // "desc"
参数解析的源码实现
1. 动态路由参数的匹配机制
路由匹配的核心逻辑在create-route-map.js中实现,该模块负责将路由配置转换为可匹配的路径规则:
// [src/create-route-map.js](https://link.gitcode.com/i/6416f0ee775b76edc1bb084b0c780fb7)
function addRouteRecord (
pathList: Array<string>,
pathMap: Dictionary<RouteRecord>,
nameMap: Dictionary<RouteRecord>,
route: RouteConfig,
parent?: RouteRecord,
matchAs?: string
) {
const { path, name } = route
// 处理路径中的动态参数
const normalizedPath = normalizePath(path, parent, pathList)
const record: RouteRecord = {
path: normalizedPath,
regex: pathToRegexp(normalizedPath, keys, options),
keys, // 存储参数名信息
components: route.components || { default: route.component },
// ...其他属性
}
// 添加到路径映射表
pathMap[normalizedPath] = record
}
路径匹配使用path-to-regexp库将路径字符串转换为正则表达式,例如/user/:id会被转换为匹配/user/123的正则,并提取id参数。
2. 参数提取与路由匹配
当调用router.push或点击<router-link>时,路由系统会执行transitionTo方法进行路径切换:
// [src/history/base.js](https://link.gitcode.com/i/32e8e625c2c0ea7ab0f4cd6f0192b032)
transitionTo (location: RawLocation, onComplete?: Function, onAbort?: Function) {
const route = this.router.match(location, this.current)
this.confirmTransition(route, () => {
this.updateRoute(route)
// ...其他逻辑
}, onAbort)
}
match方法通过路径匹配找到对应的路由记录,并提取参数:
// [src/index.js](https://link.gitcode.com/i/ce6502334bdf2362b678c0d907da1a18)
match (
raw: RawLocation,
current?: Route,
redirectedFrom?: Location
): Route {
const location = normalizeLocation(raw, current, false, this)
const { name } = location
if (name) {
// 按名称匹配逻辑
} else if (location.path) {
// 按路径匹配逻辑
location.params = {}
for (let i = 0; i < pathList.length; i++) {
const path = pathList[i]
const record = pathMap[path]
if (match = record.regex.exec(location.path)) {
// 提取参数
const params: Object = {}
for (let i = 1; i < match.length; i++) {
const key = record.keys[i - 1]
const val = match[i] !== undefined ? decodeURIComponent(match[i]) : undefined
params[key.name] = val
}
location.params = params
return _createRoute(record, location, redirectedFrom)
}
}
}
}
3. Query参数的处理逻辑
Query参数的解析相对简单,使用querystring库解析URL中的查询字符串部分:
// [src/util/query.js](https://link.gitcode.com/i/e379125d5b948ea7a9b092e340af1be5)
export function parseQuery (query: string): Object {
const res = {}
query = query.trim().replace(/^(\?|#|&)/, '')
if (!query) {
return res
}
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 (res[key] === undefined) {
res[key] = val
} else if (Array.isArray(res[key])) {
res[key].push(val)
} else {
res[key] = [res[key], val]
}
})
return res
}
参数在组件中的获取方式
1. 直接访问$route对象
组件中可通过this.$route.params和this.$route.query直接访问参数:
// 组件内部
export default {
mounted() {
console.log(this.$route.params.id) // 动态参数
console.log(this.$route.query.page) // 查询参数
}
}
$route是通过Vue原型注入的响应式对象:
// [src/install.js](https://link.gitcode.com/i/93d04991bc5c19023fa0b5d606e7a724)
Object.defineProperty(Vue.prototype, '$route', {
get () { return this._routerRoot._route }
})
2. 使用路由 props 解耦
为避免组件与$route强耦合,可使用props选项将参数注入组件:
// 路由配置
const routes = [
{
path: '/user/:id',
component: User,
props: true // 将params转换为组件props
},
{
path: '/search',
component: Search,
// 函数模式,可处理query参数
props: (route) => ({
keyword: route.query.keyword,
page: route.query.page || 1
})
}
]
// 组件中直接使用props
export default {
props: ['id', 'keyword', 'page'],
mounted() {
console.log(this.id) // 来自params
console.log(this.keyword) // 来自query
}
}
参数变化的检测与响应
1. 监听$route对象
当路由参数变化但组件被复用时(如从/user/1到/user/2),组件不会重新创建,需通过watch监听参数变化:
export default {
watch: {
'$route'(to, from) {
// 处理参数变化逻辑
this.loadUser(to.params.id)
},
// 或只监听特定参数
'$route.params.id'(id) {
this.loadUser(id)
}
}
}
2. 使用beforeRouteUpdate导航守卫
组件内导航守卫也可检测参数变化:
export default {
beforeRouteUpdate(to, from, next) {
// 在导航完成前获取参数
this.id = to.params.id
this.loadUser(this.id)
next()
}
}
源码中的参数安全处理
Vue-Router 对参数进行了多方面的安全处理:
- URL编码/解码:参数在存储和传递过程中会进行URI编码,避免特殊字符问题
// [src/util/query.js](https://link.gitcode.com/i/e379125d5b948ea7a9b092e340af1be5)
function encodeQuery (obj: Dictionary<any>): string {
const parts: string[] = []
for (const key in obj) {
const val = obj[key]
if (val === undefined) return ''
if (val === null) continue
if (Array.isArray(val)) {
val.forEach(v => {
parts.push(encode(key) + '=' + encode(v))
})
} else {
parts.push(encode(key) + '=' + encode(val))
}
}
return parts.join('&')
}
- 重复导航检测:避免相同参数的重复导航
// [src/history/base.js](https://link.gitcode.com/i/32e8e625c2c0ea7ab0f4cd6f0192b032)
confirmTransition (route: Route, onComplete: Function, onAbort?: Function) {
const current = this.current
if (
isSameRoute(route, current) &&
route.matched.length === current.matched.length
) {
this.ensureURL()
return abort()
}
// ...其他逻辑
}
最佳实践与性能优化
-
参数使用建议:
- 资源标识用Params(如
/user/:id) - 筛选条件用Query(如
/list?page=1&sort=desc) - 复杂状态考虑使用Vuex管理而非URL参数
- 资源标识用Params(如
-
性能优化:
- 使用
props解耦路由参数,提高组件复用性 - 对频繁变化的参数使用
v-model配合$router.push而非直接修改$route - 合理使用
keep-alive缓存组件时,注意参数变化的监听
- 使用
-
安全注意事项:
- 避免在URL中传递敏感信息
- 服务端渲染(SSR)时需对参数进行验证和过滤
总结
Vue-Router 通过路径正则匹配和查询字符串解析,实现了灵活的路由参数处理机制。核心流程包括:
- 路由配置转换为匹配规则(含参数定义)
- 路径匹配时提取Params和Query参数
- 通过
$route对象或props注入组件 - 提供参数变化检测机制
理解参数传递的源码实现,有助于开发者在复杂场景下选择合适的参数传递方式,并编写更健壮的路由逻辑。完整的路由参数处理源码可参考:
- 路由匹配:src/create-route-map.js
- 参数解析:src/util/query.js
- 路由守卫:src/history/base.js
- 组件注入:src/install.js
【免费下载链接】vue-analysis :thumbsup: Vue.js 源码分析 项目地址: https://gitcode.com/gh_mirrors/vu/vue-analysis
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



