Vue Router里的query props该怎么用?要注意啥?
不少做前端开发的同学在玩Vue项目时,碰到Vue Router的query和props结合使用,总会犯嘀咕——这俩咋配合能让组件传参更顺?query props到底能解决啥问题?今儿咱就掰开揉碎了聊聊Vue Router里query props的那些事儿,从基础用法到实际场景,再到避坑技巧,一次讲明白。
query和props在Vue Router里分别是干啥的?
先把基础概念理清楚。query 是路由中 URL 里 后面跟着的参数,/page?name=张三&age=18
里,name
和 age
query 参数,它属于路由信息($route
)的一部分,作用更像“附加筛选条件”或者“页面状态标记”。
而 props 是 Vue 组件接收外部数据的核心方式,父组件通过 props
把数据传给子组件,子组件用 props
选项声明后就能用,这种方式让组件依赖更清晰,也方便测试(不用关心父组件咋来的,传数据就行)。
Vue Router 里搞了个“骚操作”:能把路由的 query
参数直接映射成组件的 props
,这么做的好处是 让组件和路由解耦 —— 组件不用直接去读 this.$route.query
,改成用 props
接收,后续换路由逻辑或者测试组件时,直接传模拟数据就行,灵活度拉满!
怎么把query参数转成组件props?
这得在路由配置里动刀子,Vue Router 给 props
配置提供了三种玩法:布尔值、对象、函数,咱重点看和 query 结合的场景:
布尔值模式(简单映射)
如果路由配置里写 props: true
,Vue Router 会自动把 route.query
里的所有参数,一股脑传给组件当 props
,举个栗子:
// 路由配置 { path: '/search', component: SearchComponent, props: true } // 组件里声明props export default { props: ['keyword', 'page'], // query里的keyword、page会被传进来 mounted() { console.log(this.keyword, this.page); // 直接用props,不用碰$route } }
这种方式适合 query 参数少、不需要额外处理的场景,但灵活性弱(没法改参数名、加默认值)。
函数模式(自定义处理)
要是想对 query 参数做“加工”(比如改名字、加默认值、转类型),用函数模式更爽,路由配置里的 props
可以是个函数,接收 route
对象当参数,返回要传给组件的 props
对象。
// 路由配置 { path: '/goods', component: GoodsList, props: (route) => { return { // query里的page是字符串,转成数字 currentPage: Number(route.query.page) || 1, // 给分类加默认值,没传就显示“全部” category: route.query.category || '全部' }; } } // 组件里声明props export default { props: { currentPage: { type: Number, required: true }, category: { type: String, default: '全部' } }, created() { this.fetchGoods(this.currentPage, this.category); // 用props发请求 } }
这种方式能灵活处理 query 参数,比如类型转换、默认值、参数重命名,组件里的 props
也能更“干净”(不用兼容路由里的参数名)。
用query props有啥好处?
很多同学会疑惑:直接用 this.$route.query
也能拿参数,为啥非得绕个 props
?这就得聊聊解耦、可维护、可测试这几个关键点了:
组件和路由解耦,测试更简单
如果组件里直接用 this.$route.query
,测试时得模拟整个路由对象,特麻烦,但用 props
接收的话,测试组件时直接传假数据就行,比如测试 GoodsList
组件,不用管路由,直接传 { currentPage: 2, category: '手机' }
就能测,清爽!
参数处理集中化,组件更纯粹
路由配置里把 query 转 props 的逻辑(比如类型转换、默认值)集中处理,组件只负责“渲染/逻辑”,不用关心参数从哪来、咋处理的,相当于把“路由层”和“组件层”的职责分开,代码维护起来更顺。
符合单向数据流,Bug 好排查
Vue 里 props 是“父传子”的单向数据流,路由作为“父”把 query 处理后传给组件,组件里 props 变化能清晰追踪,要是直接用 $route
,参数变化时组件可能没感知,容易埋 Bug;用 props 的话,配合 watch
或者组件更新机制,能更及时响应变化。
实际开发中哪些场景适合用query props?
别光讲理论,咱结合真实场景唠唠,你就知道这玩意儿多实用了:
列表页带筛选/分页参数
比如电商平台的商品列表,用户选了“价格区间”“分类”“排序方式”,这些筛选条件存在 URL 的 query 里(刷新页面能保留状态),用 query props 把这些参数传给列表组件,组件拿到参数后请求对应数据。
路由配置大概长这样:
{ path: '/products', component: ProductList, props: (route) => ({ priceRange: route.query.priceRange || '0-∞', category: route.query.category || 'all', sort: route.query.sort || 'new', page: Number(route.query.page) || 1 }) }
组件里用这些 props 发请求,用户刷新页面,筛选条件还在,体验拉满。
多 Tab 切换保存状态
页面里有多个 Tab(待付款”“待发货”“已完成”),把当前激活的 Tab 标识(activeTab=waitPay
)存在 query 里,用 query props 传给 Tab 组件,切换 Tab 时改 URL query,刷新页面 Tab 状态不丢。
举个简单实现:
// 路由配置 { path: '/order', component: OrderPage, props: (route) => ({ activeTab: route.query.activeTab || 'waitPay' }) } // 组件里,点击Tab时修改query import { useRouter } from 'vue-router'; export default { props: ['activeTab'], setup(props) { const router = useRouter(); const changeTab = (tab) => { router.push({ query: { activeTab: tab } }); // 改query,触发props更新 }; return { changeTab, props }; } }
搜索页传关键词
搜索页面的关键词一般存在 query 里(/search?keyword=Vue
),用 query props 把 keyword
传给搜索组件,组件拿到关键词直接请求搜索接口,就算用户分享 URL,别人打开也能直接看到对应搜索结果,SEO 和体验都照顾到了。
配置query props时容易踩的坑有哪些?
前端开发哪有不踩坑的?提前避坑才能少掉头发,这些常见问题得注意:
参数类型不匹配,组件报错
query 里的参数默认都是字符串!比如你想传 page: 2
,但 route.query.page
拿到的是 '2'
,如果组件 props 声明的是 Number
类型,直接赋值会报错(字符串转数字失败)。
解决办法:在路由的 props
函数里手动转类型。
props: (route) => ({ page: Number(route.query.page) || 1 // 转成数字,没传就给默认值1 })
默认值没处理,props 变成 undefined
query 里没传某个参数,route.query.xxx
会是 undefined
,要是组件 props 没给默认值,直接用的时候就会报错(props.xxx.length
会崩)。
解决办法:在路由 props
函数里给默认值,或者组件 props 里声明 default
,推荐在路由层处理,因为路由更清楚“这个参数不传时该用啥默认值”。
同路由组件复用,props 不更新
Vue Router 有个机制:如果路由路径不变,只是 query 变了,组件会被复用(不会销毁重建),这时候 props 默认不会自动更新,组件里可能还拿着旧数据。
解决办法有两种:
- 用
watch
监听 props 变化,watch(() => props.page, (newVal) => { /* 发请求 */ })
; - 给组件加
key
,用 query 参数当 key,强制组件重建:<component :key="$route.fullPath" />
(但性能略差,谨慎用)。
和params比,query props在传参上有啥不同?
很多同学分不清 query
和 params
,这里简单对比下:
维度 | query 参数 | params 参数 |
---|---|---|
存储位置 | URL 中 后面(如 /page?name=xx ) |
URL 路径里(如 /user/:id → /user/123 ) |
刷新保留 | 刷新页面,参数还在 | 刷新页面,参数也在(只要路由配置对) |
传参场景 | 筛选条件、页面状态(非核心标识) | 资源唯一标识(如用户ID、商品ID) |
props 映射 | 靠 props: true 或函数映射 query |
也能 props: true 映射 params(路由配置要写 /:id ) |
简单说,params
更像“资源的身份证”,query
更像“资源的筛选器”,比如做用户详情页,用 params
(/user/123
);做用户列表筛选,用 query
(/users?gender=male&page=1
)。
怎么给query props加验证?
组件的 props
本身支持类型验证、必填验证、自定义验证,这步不能省!不然传错参数很难查,举个规范的例子:
export default { props: { // 分页页码,必须是数字且大于0 page: { type: Number, required: true, validator: (value) => { return value > 0; } }, // 分类,可选,默认值在路由层处理过,这里兜底 category: { type: String, default: 'all' } } }
这样配置后,要是路由传参不符合要求(page
传了 0
或者字符串),Vue 会在控制台报错,帮你快速定位问题。
在组合式API(Composition API)里咋用query props?
用 <script setup>
或者 setup()
语法时,接收 props 更简单了,用 defineProps
就行:
<template> <div>当前页码:{{ currentPage }}</div> </template> <script setup> import { defineProps } from 'vue'; // 声明props const props = defineProps(['currentPage', 'category']); // 直接用props.currentPage console.log(props.currentPage); </script>
路由配置和之前一样,用 props
函数处理 query 传给组件,要是想在 setup 里监听 props 变化,用 watch
:
<script setup> import { defineProps, watch } from 'vue'; const props = defineProps(['currentPage']); watch( () => props.currentPage, (newPage) => { console.log('页码变了,发请求:', newPage); }, { immediate: true } // 初始化时执行一次 ); </script>
总结一下
Vue Router 的 query props 本质是把路由的查询参数,通过组件 props 传递,让组件和路由解耦,从配置方式(布尔值、函数)到实际场景(列表筛选、Tab 状态、搜索关键词),再到避坑技巧(类型转换、默认值、组件复用),掌握这些点后,写路由传参的代码会更规范、更好维护。
记住核心逻辑:路由负责处理 URL 里的 query,组件负责用 props 接收干净的数据,把这层关系理清楚,不管是现在的项目迭代,还是以后换路由方案,组件都能稳如老狗~
要是你还有其他关于 Vue Router 或者前端的问题,评论区喊我,咱接着唠!
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。