Vue Router 怎么处理多个参数?从配置到传参再到页面使用全解析
在Vue项目开发中,经常会碰到需要给路由传递多个参数的情况,像电商详情页要同时传商品ID和分类ID、后台管理列表要带搜索关键词和分页信息这些场景,很多刚接触Vue Router的小伙伴会犯愁:“Vue Router 怎么处理多个参数?” 这篇文章从路由配置、传参方法、参数获取,到实战场景和避坑技巧,把多个参数的玩法拆解得明明白白,新手也能跟着一步步搞懂~
路由里多个参数的配置逻辑
要让路由能接收多个参数,得先搞清楚两种常见配置思路:动态路由参数(动态段)和查询参数(query)。
动态路由参数配置
动态段是路由 path 里用 开头的占位符,用来匹配 URL 里的动态部分,比如做商品详情页,需要同时传商品 ID 和分类 ID,路由可以这么配:
const routes = [
{
path: '/product/:productId/:categoryId',
name: 'ProductDetail',
component: ProductDetail
}
]
这里 productId 和 categoryId 是动态段,当用户访问 /product/123/456 时,Vue Router 会把 123 和 456 分别对应到 productId 和 categoryId,存到 $route.params 里。
这种配置的特点是 参数是 URL 路径的一部分:用户分享链接时参数不会丢,且这些参数是访问页面的“必要条件”——少一个参数,页面可能无法正常渲染(比如商品 ID 丢了,就查不到对应商品数据)。
查询参数配置
查询参数不用改路由的 path,而是通过 后面的键值对传递,适合传“可选参数”,比如后台订单列表的搜索页,需要关键词、分页、状态等筛选条件,路由可以这么配:
const routes = [
{
path: '/admin/order',
name: 'OrderList',
component: OrderList
}
]
访问时 URL 是 /admin/order?keyword=手机&page=2&status=待发货,这些 keyword、page、status 就是查询参数,存到 $route.query 里。
查询参数的优势是 灵活可选:页面能根据有无参数做不同逻辑,刷新后参数也会保留,但它们不是 URL 路径的“必须部分”——就算不传,页面也能打开(比如默认展示第一页、所有状态的订单)。
动态段适合传“必要且固定在路径里”的参数,查询参数适合传“可选且拼接在路径后”的参数,实际项目里常结合两种方式:比如商品详情页用动态段传商品 ID 和分类 ID,再用查询参数传“是否显示推荐”这类可选配置。
给路由传多个参数的不同方式
知道了怎么配置路由,接下来得搞清楚怎么往路由里传多个参数,Vue Router 提供了好几种传参方式,不同场景选不同方式更顺手~
动态路由传参(配合动态段)
如果路由里配了动态段(比如前面的 /product/:productId/:categoryId),传参时要把参数拼到 URL 里,有两种常用写法:
-
<router-link>组件传参:用模板字符串把参数拼起来<router-link :to="`/product/${productId}/${categoryId}`"> 查看商品详情 </router-link>这里
productId和categoryId是组件里的变量,点击后 URL 会变成/product/实际ID/实际分类ID,参数会被解析到$route.params里。 -
编程式导航传参:用
this.$router.push拼接路径this.$router.push(`/product/${this.productId}/${this.categoryId}`)这种方式和
<router-link>原理一样,适合在点击按钮、接口回调等逻辑里触发路由跳转。
动态路由传参的特点是 参数强制可见——必须把参数拼到 URL 里才能访问对应页面,适合“没参数就开不了页”的场景(比如商品详情页没商品 ID 就查不到数据)。
查询参数(query)传参
查询参数传参不需要改路由的 path,而是把参数放到 query 对象里,同样分 <router-link> 和编程式导航两种写法:
-
<router-link>传 query:通过to的对象语法传<router-link :to="{ path: '/search', query: { keyword: searchKeyword, page: currentPage } }" > 搜索 </router-link>这里
searchKeyword和currentPage是组件内的变量,点击后 URL 会变成/search?keyword=xxx&page=xx,参数存在$route.query里。 -
编程式导航传 query:用
push的对象语法this.$router.push({ path: '/search', query: { keyword: this.searchKeyword, page: this.currentPage } })
查询参数的优势是 灵活可缺省:就算不传某个参数,页面也能正常打开(比如默认 page=1),而且多个参数可以自由组合,适合筛选、分页这类“多条件可选”的场景。
命名路由结合 params 传参
如果路由配了 name(name: 'ProductDetail'),还可以用 params 对象传参,但要注意:用 params 传参时,必须配合 name,不能用 path(因为 path 和 params 一起用会被 Vue Router 忽略),写法如下:
-
<router-link>传 params:<router-link :to="{ name: 'ProductDetail', params: { productId: productId, categoryId: categoryId } }" > 查看商品详情 </router-link> -
编程式导航传 params:
this.$router.push({ name: 'ProductDetail', params: { productId: this.productId, categoryId: this.categoryId } })
这种方式的参数会不会显示在 URL 里?要看路由有没有配动态段:
- 如果路由
path是/product/:productId/:categoryId,params里的参数会被解析到 URL 路径中; - 如果路由
path是/product(没配动态段),params里的参数不会显示在 URL 里,且刷新页面后参数会丢失。
所以这种方式更适合“参数必须在 URL 里体现,且路由已经配好动态段”的场景,相当于动态路由传参的“命名路由版”。
页面中怎么获取多个路由参数
路由把参数传过来了,页面组件里怎么拿到这些参数?关键是要熟悉 $route 对象里的 params 和 query~
动态路由参数:$route.params
动态路由的参数存在 this.$route.params 里,直接取对应的键就行,比如在 ProductDetail 组件里:
<template>
<div>
<h1>当前商品ID:{{ productId }}</h1>
<h2>所属分类ID:{{ categoryId }}</h2>
</div>
</template>
<script>
export default {
data() {
return {
productId: '',
categoryId: ''
}
},
created() {
// 组件创建时,从 $route.params 拿参数
this.productId = this.$route.params.productId
this.categoryId = this.$route.params.categoryId
// 拿到参数后请求商品数据
this.fetchProduct()
},
methods: {
fetchProduct() {
// 用 productId 和 categoryId 发请求,
// axios.get(`/api/product/${this.productId}?category=${this.categoryId}`)
}
}
}
</script>
但这里有个坑:如果路由参数变化了,但组件没被销毁(比如从 /product/1/2 跳到 /product/3/2,组件还是 ProductDetail),created 钩子不会再执行,这时候参数更新了,页面数据却没变化,怎么解决?
-
用
watch监听$route的变化:watch: { '$route'(to) { // to 是新的路由对象,from 是旧的(可省略) this.productId = to.params.productId this.categoryId = to.params.categoryId this.fetchProduct() // 重新请求数据 } } -
或者用 Vue Router 提供的
beforeRouteUpdate导航守卫:beforeRouteUpdate(to, from, next) { this.productId = to.params.productId this.categoryId = to.params.categoryId this.fetchProduct() next() // 必须调用 next() 才能继续导航 }
查询参数:$route.query
查询参数存在 this.$route.query 里,获取方式和 params 类似,比如在 SearchPage 组件里处理搜索关键词和分页:
<template>
<div>
<input v-model="keyword" placeholder="请输入关键词" />
<button @click="handleSearch">搜索</button>
<div>当前页码:{{ page }}</div>
</div>
</template>
<script>
export default {
data() {
return {
keyword: '',
page: 1
}
},
created() {
// 从 query 里拿初始参数(比如页面刷新后,保留之前的搜索条件)
this.keyword = this.$route.query.keyword || ''
this.page = this.$route.query.page || 1
},
watch: {
'$route'(to) {
// 路由变化时(比如用户点击分页按钮,路由 query 变化)
this.keyword = to.query.keyword || ''
this.page = to.query.page || 1
this.fetchSearchResult()
}
},
methods: {
handleSearch() {
this.$router.push({
path: '/search',
query: { keyword: this.keyword, page: this.page }
})
},
fetchSearchResult() {
// 根据 keyword 和 page 发请求,
// axios.get(`/api/search?keyword=${this.keyword}&page=${this.page}`)
}
}
}
</script>
查询参数同样要注意“组件复用导致数据不更新”的问题,所以也要用 watch 或导航守卫来处理参数变化。
用计算属性或侦听器简化代码
如果组件里要频繁用 $route.params 或 $route.query,可以用计算属性把参数“封装”一下,让模板更简洁。
<template>
<div>
<h1>商品ID:{{ productId }}</h1>
<h2>分类ID:{{ categoryId }}</h2>
</div>
</template>
<script>
export default {
computed: {
productId() {
return this.$route.params.productId
},
categoryId() {
return this.$route.params.categoryId
}
},
created() {
this.fetchProduct()
},
watch: {
productId() {
this.fetchProduct()
},
categoryId() {
this.fetchProduct()
}
},
methods: {
fetchProduct() {
// 发请求逻辑
}
}
}
</script>
这样模板里直接用 productId 和 categoryId,不用每次都写 this.$route.params.xxx,代码更干净~
多参数路由的实战场景举例
光讲理论不够直观,结合实际项目场景看看多参数路由怎么用~
电商商品详情页(动态路由多参数)
需求:用户点商品卡片进入详情页,需要展示商品信息和所属分类下的推荐商品,这时候商品 ID 和分类 ID 都是必要参数,必须放在 URL 路径里,所以用动态路由。
-
路由配置:
{ path: '/product/:productId/:categoryId', name: 'ProductDetail', component: ProductDetail } -
传参(以编程式导航为例):
用户点商品卡片时,触发方法:handleProductClick(productId, categoryId) { this.$router.push(`/product/${productId}/${categoryId}`) } -
组件内获取参数并请求数据:
<template> <div> <div v-if="loading">加载中...</div> <div v-else> <h1>{{ productInfo.title }}</h1> <p>{{ productInfo.desc }}</p> <h2>同分类推荐</h2> <ul> <li v-for="item in relatedProducts" :key="item.id">{{ item.title }}</li> </ul> </div> </div> </template> <script> import axios from 'axios' export default { data() { return { loading: true, productInfo: {}, relatedProducts: [] } }, created() { this.fetchData() }, watch: { '$route'() { this.fetchData() } }, methods: { async fetchData() { this.loading = true const { productId, categoryId } = this.$route.params // 请求商品详情 const productRes = await axios.get(`/api/product/${productId}`) // 请求同分类推荐商品 const relatedRes = await axios.get(`/api/category/${categoryId}/products`) this.productInfo = productRes.data this.relatedProducts = relatedRes.data this.loading = false } } } </script>
这里用动态路由把必要参数放 URL 里,既保证了页面分享的完整性,又让 SEO 更友好(搜索引擎能抓取到不同商品页的 URL)。
后台管理系统的订单列表(查询参数多参数)
需求:订单列表需要支持关键词搜索、分页、状态筛选,而且刷新页面后筛选条件要保留,这时候筛选条件是可选的,适合用查询参数。
-
路由配置:
{ path: '/admin/order', name: 'OrderList', component: OrderList } -
传参(以
<router-link>为例,假设当前页是第 2 页,搜索关键词是“手机”,状态是“待发货”):<router-link :to="{ path: '/admin/order', query: { keyword: '手机', page: 2, status: '待发货' } }" > 查看筛选后的订单 </router-link> -
组件内获取参数并请求数据:
<template> <div> <input v-model="keyword" placeholder="搜索关键词" /> <select v-model="status"> <option value="">全部状态</option> <option value="待支付">待支付</option> <option value="待发货">待发货</option> </select> <button @click="handleFilter">筛选</button> <div class="pagination"> <button @click="handlePageChange(1)">第1页</button> <button @click="handlePageChange(2)">第2页</button> </div> <table> <tr v-for="order in orderList" :key="order.id"> <td>{{ order.id }}</td> <td>{{ order.name }}</td> <td>{{ order.status }}</td> </tr> </table> </div> </template> <script> import axios from 'axios' export default { data() { return { keyword: '', status: '', page: 1, orderList: [] } }, created() { // 从 query 里拿初始参数 this.keyword = this.$route.query.keyword || '' this.status = this.$route.query.status || '' this.page = this.$route.query.page || 1 this.fetchOrders() }, watch: { '$route'() { // 路由变化时(比如用户点分页按钮,query 变化) this.keyword = this.$route.query.keyword || '' this.status = this.$route.query.status || '' this.page = this.$route.query.page || 1 this.fetchOrders() } }, methods
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
code前端网


