Vue Router push 咋传 query params?传完咋处理?这篇讲透!
在Vue项目里做页面跳转,传递参数是绕不开的需求,尤其是query params,既能让参数留在URL里(刷新不丢),又不用在路由里提前配置,灵活得很~但刚上手时,不少同学会懵:“咋用router.push传query?传过去咋拿?参数变了页面不更新咋办?”今天从基础用法到踩坑解决,把query params的逻辑拆得明明白白,看完就能落地干活~
先搞懂:Vue Router的query params是啥?
咱先举个生活例子:打开淘宝搜索“手机”,URL可能是 https://s.taobao.com/search?q=手机&sort=sale-desc
,这里 q=手机
和 sort=sale-desc
就是query params——它们以 ?key=value
的形式附加在URL后面,和路由路径(/search
)是分离的。
对比另一种传参方式 params(比如路由写 /user/:id
,参数藏在路径里),query有这些特点:
- 无需提前配置路由:不用在路由规则里写
/xxx/:key
,想传啥参数直接塞query里; - 刷新不丢参数:因为参数在URL里,页面刷新后还能保留(比如搜索页的筛选条件,刷新后不想丢就适合用query);
- 参数更灵活:可以传多个键值对,甚至复杂数据(但要自己处理序列化哦)。
核心操作:用router.push传query params
Vue Router里用 this.$router.push()
实现“编程式导航”,传query参数要在配置对象里加 query
字段,值是对象,下面分两种常见写法讲:
(1)用 path
指定跳转路径
直接写目标页面的路径,然后把参数塞到 query
里:
// 假设在组件方法里,点击按钮跳转 goToDetail() { const productId = 123; this.$router.push({ path: '/product-detail', // 目标页面的路径 query: { id: productId, // 要传的参数:商品ID tab: 'info' // 额外参数:默认显示info tab } }); }
执行后,URL会变成 /product-detail?id=123&tab=info
,参数自动拼在后面。
(2)用 name
(配合路由“命名”)
如果路由配置时给页面起了名字(name: 'ProductDetail'
),也可以用 name
跳转:
this.$router.push({ name: 'ProductDetail', // 路由配置里的name query: { id: productId, tab: 'info' } });
这种方式更“语义化”,Vue会先找到路由配置里的 path
,再把query参数拼到URL上,效果和用 path
一样。
(3)传复杂数据(对象/数组)咋处理?
如果直接传对象,Vue Router会把它转成 [object Object]
这种无效格式,所以得先序列化(比如用 JSON.stringify
),接收时再解析( JSON.parse
),举个例子:
// 传递端:把筛选条件对象序列化 const filter = { brand: '华为', price: [1000, 5000] }; this.$router.push({ path: '/search', query: { filter: JSON.stringify(filter) } }); // 接收端:解析序列化后的字符串 created() { const filterStr = this.$route.query.filter; const filter = JSON.parse(filterStr); console.log(filter.brand); // 输出:华为 }
目标页面咋拿query params?
跳转后,在目标组件里,通过 this.$route.query
就能拿到参数~ $route
是Vue Router提供的当前路由信息对象,里面的 query
就是传递的参数键值对。
(1)基础用法:直接取参数
比如详情页要拿商品ID,代码可以这么写:
export default { name: 'ProductDetail', created() { // 解构赋值拿参数 const { id, tab } = this.$route.query; console.log('商品ID:', id); // 注意:这里id是字符串!比如传的123,拿到的是"123" console.log('当前tab:', tab); // 同理,tab也是字符串 // 调用接口请求数据(记得转类型!) this.fetchProductDetail(Number(id)); }, methods: { fetchProductDetail(productId) { // 实际接口请求逻辑... } } }
(2)关键细节:参数类型转换
因为query参数在URL里是字符串,所以如果传的是数字、布尔值,拿到后要手动转类型,比如传了 id: 123
,目标组件里 this.$route.query.id
是 "123"
,如果接口需要数字,得用 Number(id)
转换。
传递query params的“坑”与解决
用query传参时,有些场景容易踩坑,比如刷新后参数残留、同一组件参数变化但页面不更新……下面逐个拆解:
(1)刷新页面后,参数还在,要不要清?
场景:表单提交后跳转到成功页,不想让用户刷新后还看到之前的参数。
解决:跳转时把query置空,或者只清特定参数:
// 方式1:清空所有query参数 this.$router.push({ path: '/success', query: {} }); // 方式2:只清空某个参数(保留其他参数) this.$router.push({ path: '/list', query: { ...this.$route.query, // 保留原有参数 keyword: undefined // 清空keyword参数 } });
(2)同一组件内,query变了页面没反应?
问题:比如从 /product?tab=info
跳到 /product?tab=comment
,因为是同一个组件(ProductDetail),Vue不会销毁重建组件,created
钩子不会再执行,数据也不更新。
解决方法1:用watch监听$route.query
在组件里写 watch
,监听query变化时触发逻辑:
export default { watch: { '$route.query'(newQuery, oldQuery) { const { tab } = newQuery; this.switchTab(tab); // 切换tab的逻辑 } }, methods: { switchTab(tab) { // 切换tab的逻辑... } } }
解决方法2:用路由守卫beforeRouteUpdate
路由守卫 beforeRouteUpdate
会在“同一组件,路由参数变化时”触发,适合在跳转前处理逻辑:
export default { beforeRouteUpdate(to, from, next) { const { tab } = to.query; this.switchTab(tab); next(); // 必须调用next()放行路由跳转 }, methods: { switchTab(tab) { // 切换tab的逻辑... } } }
(3)多个参数传递,重复写太麻烦?
场景:列表页有分页(page)、搜索词(keyword)、排序(sort)多个参数,只想改page,其他保留。
解决:用扩展运算符合并当前query,只改需要的参数:
// 当前路由的query是 { page: 1, keyword: '手机', sort: 'price' } // 跳转到第2页,其他参数保留 this.$router.push({ path: '/list', query: { ...this.$route.query, // 保留原有参数 page: 2 // 只改page } });
(4)参数太多,URL变得很长很难看?
问题:传一堆筛选条件,URL变成 ?filter=...&page=...&sort=...
,又长又暴露信息。
解决思路:
- 只传关键ID,其他参数从接口拉:比如列表页传商品ID,详情页根据ID重新请求所有数据,不用传冗余参数;
- 加密参数:把复杂参数加密成字符串,传加密后的值,接收端解密(适合对安全性有要求的场景);
- 用缓存暂存:把非关键参数存在
sessionStorage
/localStorage
里,只传必要的标识(比如缓存key)。
实战:列表→详情页传参案例
以电商项目为例,商品列表页点击商品,跳转到详情页并传递商品ID,详情页根据ID请求数据。
列表页(GoodsList.vue):点击传参
<template> <div class="goods-list"> <div v-for="goods in goodsList" :key="goods.id" @click="toDetail(goods.id)" > {{ goods.name }} - 价格{{ goods.price }} </div> </div> </template> <script> export default { data() { return { goodsList: [ { id: 1, name: '笔记本', price: 5999 }, { id: 2, name: '平板电脑', price: 3999 } ] } }, methods: { toDetail(goodsId) { this.$router.push({ name: 'GoodsDetail', // 路由配置里的name query: { id: goodsId, from: 'list' // 标记来源(可选) } }); } } } </script>
详情页(GoodsDetail.vue):拿参 & 处理变化
<template> <div class="goods-detail"> <h1>{{ goodsInfo.name }}</h1> <p>价格:{{ goodsInfo.price }}</p> <p>参数:{{ goodsInfo.params }}</p> <button @click="switchTab('params')">参数tab</button> <button @click="switchTab('comment')">评价tab</button> </div> </template> <script> export default { data() { return { goodsInfo: {}, activeTab: 'params' } }, created() { this.fetchGoods(); // 初始化请求数据 }, watch: { '$route.query'(newQuery) { // 如果从其他页面跳过来(比如推荐页),重新请求数据 this.fetchGoods(); // 如果是tab变化,切换tab if (newQuery.tab) { this.activeTab = newQuery.tab; } } }, methods: { async fetchGoods() { const { id } = this.$route.query; if (!id) return; // 防止无ID时请求 const res = await this.$api.getGoodsDetail(Number(id)); // 接口请求 this.goodsInfo = res.data; }, switchTab(tab) { // 切换tab时,保留其他query参数,只改tab this.$router.push({ ...this.$route, // 保留当前path和其他query参数 query: { ...this.$route.query, tab: tab } }); } } } </script>
这个案例里:
- 列表页用
query
传id
和from
,灵活又直观; - 详情页用
created
初始化请求,用watch
监听query变化(比如从推荐页跳过来时重新请求); - 切换tab时,用扩展运算符保留其他参数,只改
tab
,避免URL参数丢失。
进阶:用props让组件和$route解耦
路由配置里可以用 props
选项,把query参数映射到组件props,让组件不再直接依赖 this.$route.query
,更符合“组件化思想”。
路由配置(router.js):
const routes = [ { path: '/goods-detail', name: 'GoodsDetail', component: GoodsDetail, // 把query参数映射到props props: (route) => ({ id: route.query.id, tab: route.query.tab || 'params' // 设置默认值 }) } ]
详情页组件(GoodsDetail.vue):用props接收
export default { props: { id: { type: String, required: true }, tab: { type: String, default: 'params' } }, created() { this.fetchGoods(this.id); // 直接用props里的id }, methods: { fetchGoods(productId) { // 接口请求... } } }
这样组件里不用直接操作 this.$route.query
,后期维护、测试更方便~
掌握query params的关键逻辑
- 传递:用
router.push({ path/name, query: { ... } })
,复杂数据要序列化; - 接收:目标组件用
this.$route.query
,注意类型转换(字符串转数字/对象); - 场景处理:刷新保留、同一组件参数变化、多参数合并,用
watch
/路由守卫/扩展运算符解决; - 进阶技巧:用
props
解耦组件和路由,参数太多时简化URL(加密/只传ID)。
其实query params的核心就是“URL上的参数传递与读取”,理解它和路由、组件生命周期的关系后,不管是列表传参、筛选保留、多页签切换,都能轻松应对~下次遇到类似需求,就不会慌啦~
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。