Vue Router 怎么获取 query 参数?从基础到实战一次讲透
在做 Vue 项目时,经常需要在页面跳转时传递参数,比如搜索关键词、分页页码、标签切换标识这些信息,Vue Router 里的 query 参数就是专门用来处理这类“带在 URL 上的可选参数”的,但刚接触的同学可能会疑惑:怎么在组件里拿到这些 query 参数?路由守卫里怎么获取?不同场景下有啥要注意的?今天就从基础到实战,把 Vue Router 获取 query 参数的门道一次性讲清楚~
先搞懂 Vue Router 里的 query 是啥?
很多同学会把 query 和 params 搞混,得先把概念理清楚。query 参数是跟在 URL “?” 后面的键值对,http://xxx.com/page?keyword=vue&page=2
里,keyword
和 page
query 参数,它有两个特点:
- 「可选性」:就算路由配置里没声明,也能传;
- 「刷新不丢」:页面刷新后,URL 里的 query 还在,参数不会消失。
而 params 参数是嵌在路由路径里的(path: '/user/:id'
),必须在路由配置中预先定义,而且刷新时如果路由配置没保留 params 规则,参数可能丢失,所以如果是“可选的、想暴露在 URL 上方便分享”的参数,优先用 query~
组件内怎么拿 query 参数?(分 Vue2 和 Vue3 讲)
项目里用的 Vue 版本不同,获取方式略有区别,但核心逻辑一致:通过路由实例上的 query
属性获取。
情况 1:Vue3 + 组合式 API(最常见的现代写法)
Vue3 推荐用组合式 API,配合 useRoute
函数来拿路由信息,步骤很简单:
- 先从
vue-router
里导入useRoute
; - 调用
useRoute()
拿到当前路由实例; - 用
route.query.参数名
读取值。
举个实际例子:比如做一个商品搜索页,从首页点击“搜索 vue 相关商品”后,跳转到搜索页并传 keyword=vue
,搜索页要获取这个关键词并请求数据。
跳转时的代码(比如首页的按钮点击事件):
import { useRouter } from 'vue-router' const router = useRouter() const handleSearch = () => { router.push({ name: 'SearchPage', // 假设路由命名为SearchPage query: { keyword: 'vue' } }) }
搜索页组件内获取 query:
<template> <div>当前搜索关键词:{{ keyword }}</div> </template> <script setup> import { useRoute } from 'vue-router' const route = useRoute() // 直接从route.query里拿keyword,route是响应式的,query变化时会自动更新 const keyword = route.query.keyword // 如果担心参数不存在,可设置默认值:route.query.keyword || '默认关键词' </script>
情况 2:Vue2 或 Vue3 选项式 API
如果项目还在用 Vue2,或者 Vue3 里用选项式 API(比如迁移项目时混合写法),就用 this.$route
来拿。
还是上面的搜索页例子,Vue2 选项式组件里这么写:
<template> <div>当前搜索关键词:{{ keyword }}</div> </template> <script> export default { name: 'SearchPage', data() { return { keyword: '' } }, created() { // 组件创建时,从this.$route.query里拿参数 this.keyword = this.$route.query.keyword || '默认关键词' }, watch: { // 监听$route变化(比如同路由不同query跳转时,触发更新) '$route.query'(newQuery) { this.keyword = newQuery.keyword || '默认关键词' } } } </script>
这里要注意:Vue2 中 this.$route
是响应式的,但如果是同路由跳转(比如从 /search?keyword=vue
跳到 /search?keyword=react
),组件不会重新创建,所以需要用 watch
监听 $route.query
的变化,否则参数更新了页面却不刷新~
路由守卫里怎么获取 query?
路由守卫是控制页面跳转权限、做埋点、参数处理的常用手段,不管是全局守卫、路由独享守卫,还是组件内守卫,都能通过 to
或 from
参数拿到 query~
全局守卫(router.beforeEach)
全局守卫作用于所有路由跳转,比如做登录拦截、权限验证时,经常需要看目标路由的 query 参数。
举个例子:做一个邀请注册功能,邀请链接是 http://xxx.com/register?inviteCode=12345
,需要在全局守卫里检查 inviteCode
是否有效。
路由配置文件(router/index.js)里的代码:
import { createRouter, createWebHistory } from 'vue-router' const router = createRouter({ history: createWebHistory(), routes: [/* 你的路由配置 */] }) router.beforeEach((to, from, next) => { // to 是目标路由对象,to.query 就是目标的query参数 const inviteCode = to.query.inviteCode if (inviteCode) { // 假设这里调用接口验证邀请码 checkInviteCode(inviteCode).then(valid => { if (valid) { // 验证通过,放行 next() } else { // 验证失败,跳转到错误页 next({ name: 'ErrorPage' }) } }) } else { // 没有邀请码,正常放行 next() } })
组件内守卫(以 Vue2 的 beforeRouteEnter 为例)
组件内守卫能更细粒度地控制当前组件的跳转逻辑,Vue2 里的 beforeRouteEnter
,可以在进入组件前拿到目标路由的 query。
假设个人中心页面有个需求:进入时如果 query 里带了 tab=setting
,就自动跳转到设置子页。
个人中心组件(Vue2 选项式):
export default { name: 'Profile', beforeRouteEnter(to, from, next) { // to.query 就是目标路由的query参数 const tab = to.query.tab if (tab === 'setting') { // 跳转到设置子页 next({ name: 'ProfileSetting' }) } else { next() } } }
Vue3 里组件内守卫要用到组合式 API 的 onBeforeRouteUpdate
或 onBeforeRouteLeave
,用法类似:
<script setup> import { onBeforeRouteUpdate } from 'vue-router' onBeforeRouteUpdate((to, from) => { // to.query 就是更新后的query参数 console.log('新的tab:', to.query.tab) }) </script>
实战场景:query 参数的常见用法(附代码示例)
光懂原理不够,得知道在真实项目里咋用,下面举 3 个高频场景,看完直接能抄作业~
场景 1:页面搜索状态保留(刷新/返回不丢关键词)
很多搜索页有个需求:用户输入关键词搜索后,URL 里保留关键词,刷新页面或返回时还能看到之前的搜索词,用 query 完美解决~
步骤拆解:
- 搜索输入框绑定
v-model
到keyword
; - 点击搜索按钮时,用
router.push
带query: { keyword }
跳转到自身路由(同路由跳转); - 组件创建/更新时,从
route.query
里拿keyword
赋值给输入框。
代码示例(Vue3 组合式):
<template> <div> <input v-model="keyword" placeholder="请输入搜索词" /> <button @click="handleSearch">搜索</button> <!-- 搜索结果列表 --> <SearchResult :keyword="keyword" /> </div> </template> <script setup> import { ref, onMounted } from 'vue' import { useRouter, useRoute } from 'vue-router' const router = useRouter() const route = useRoute() const keyword = ref('') // 组件挂载时,从query里拿关键词 onMounted(() => { keyword.value = route.query.keyword || '' }) const handleSearch = () => { router.push({ name: 'SearchPage', query: { keyword: keyword.value } }) } </script>
场景 2:多 tab 切换(用 query 控制显示状态)
比如个人中心有“基本信息”“订单”“设置”三个 tab,URL 里用 ?tab=info
控制显示哪个 tab,方便用户分享链接。
代码示例(Vue3 组合式):
<template> <div class="tab-bar"> <button v-for="item in tabs" :key="item.key" @click="switchTab(item.key)" :class="{ active: currentTab === item.key }" >{{ item.name }}</button> </div> <div class="tab-content"> <BasicInfo v-if="currentTab === 'info'" /> <OrderList v-if="currentTab === 'order'" /> <Setting v-if="currentTab === 'setting'" /> </div> </template> <script setup> import { computed } from 'vue' import { useRouter, useRoute } from 'vue-router' const router = useRouter() const route = useRoute() const tabs = [ { key: 'info', name: '基本信息' }, { key: 'order', name: '我的订单' }, { key: 'setting', name: '账户设置' } ] // 计算当前激活的tab:优先取query里的tab,没有则默认info const currentTab = computed(() => { return route.query.tab || 'info' }) const switchTab = (key) => { // 切换tab时,更新query参数(同路由跳转) router.push({ query: { tab: key } }) } </script> <style scoped> .active { color: red; } </style>
场景 3:分页功能(用 query 保存当前页码)
列表页做分页时,把 page
放在 query 里,这样用户刷新页面、分享链接时,能直接回到当前页。
代码示例(Vue3 组合式):
<template> <div class="page-nav"> <button @click="goPage(page - 1)" :disabled="page === 1">上一页</button> <span>第 {{ page }} 页</span> <button @click="goPage(page + 1)" :disabled="page === totalPage">下一页</button> </div> <div class="list"> <Item v-for="item in list" :key="item.id" :data="item" /> </div> </template> <script setup> import { ref, onMounted } from 'vue' import { useRouter, useRoute } from 'vue-router' import { getListData } from '@/api/list' // 假设的接口请求函数 const router = useRouter() const route = useRoute() const list = ref([]) const totalPage = ref(10) // 假设总共有10页 const page = ref(1) // 组件挂载时,从query拿page参数,请求对应页数据 onMounted(() => { const currentPage = Number(route.query.page) || 1 page.value = currentPage fetchData(currentPage) }) const fetchData = (currentPage) => { getListData({ page: currentPage }).then(res => { list.value = res.data }) } const goPage = (targetPage) => { if (targetPage < 1 || targetPage > totalPage.value) return // 跳转时更新query的page参数 router.push({ query: { ...route.query, page: targetPage } }) // 同时更新本地page值并请求数据(也可以监听route.query.page变化来请求,看需求) page.value = targetPage fetchData(targetPage) } </script>
踩坑指南:获取 query 时的常见问题 & 解决方案
用 query 时难免遇到小坑,提前避坑能少掉头发~
坑 1:query 参数是 null
或 undefined
比如跳转时没传某个参数,或者路由配置有问题,导致 route.query.xxx
拿不到值,页面渲染报错。
解决方法:给默认值!用逻辑或 或者三元表达式处理。
// 错误写法:直接拿,可能undefined const keyword = route.query.keyword // 正确写法:加默认值 const keyword = route.query.keyword || '默认关键词' // 或者更严谨(如果参数可能是空字符串): const keyword = route.query.keyword ?? '默认关键词' // ES2020的空值合并运算符
坑 2:同路由跳转 query 变化,组件没更新
比如从 /page?tab=info
跳到 /page?tab=order
,URL 变了但组件内容没变化,原因是:同路由跳转时,组件不会重新创建,created
/mounted
里的代码不会重新执行。
解决方法:
- Vue2 中用
watch
监听$route.query
; - Vue3 中用
watch
监听route.query
,或者用onBeforeRouteUpdate
钩子。
Vue3 示例(watch 监听):
<script setup> import { watch } from 'vue' import { useRoute } from 'vue-router' const route = useRoute() const currentTab = ref(route.query.tab || 'info') // 监听route.query变化,更新currentTab watch( () => route.query.tab, (newTab) => { currentTab.value = newTab || 'info' } ) </script>
Vue3 示例(onBeforeRouteUpdate):
<script setup> import { onBeforeRouteUpdate } from 'vue-router' const currentTab = ref('info') onBeforeRouteUpdate((to) => { currentTab.value = to.query.tab || 'info' }) </script>
坑 3:query 参数含特殊字符(如中文、&、=)
如果直接把特殊字符放 query 里,URL 会乱码,甚至导致参数解析错误。
解决方法:跳转前用 encodeURIComponent
编码,获取时用 decodeURIComponent
解码。
示例:传递中文关键词
// 跳转时编码 const keyword = 'Vue 教程' router.push({ name: 'SearchPage', query: { keyword: encodeURIComponent(keyword) } }) // 获取时解码 const route = useRoute() const decodedKeyword = decodeURIComponent(route.query.keyword || '')
进阶:query 参数的结构化处理(封装复用)
如果项目里很多地方要处理 query 参数,每次都写“拿参数 + 处理默认值 + 类型转换”很冗余,可以封装一个工具函数或 composable,让代码更简洁~
封装 useQueryParams(Vue3 组合式)
比如做一个通用的 useQueryParams
,支持传参数名、默认值、类型转换函数。
// 新建 hooks/useQueryParams.js import { useRoute } from 'vue-router' export const useQueryParams = (key, options = {}) => { const route = useRoute() const { defaultValue = '', transform = (v) => v } = options // 获取query参数,处理默认值和转换 const value = transform(route.query[key] || defaultValue) return value }
使用示例:处理分页的 page 参数(转数字)
<script setup> import { useQueryParams } from '@/hooks/useQueryParams' // 获取page参数,默认1,转数字 const page = useQueryParams('page', { defaultValue: '1', transform: (v) => Number(v) }) </script>
这样一来,不管是处理字符串、数字还是布尔值,都能通过 transform
函数统一处理,代码复用性拉满~
Vue Router 获取 query 参数的核心逻辑很简单:在组件里通过 `useRoute`(Vue3)或 `this.$route`(Vue2)拿,路由守卫里通过 `to.query` 拿,但真正用起来,得结合场景考虑默认值、响应式更新、特殊字符处理这些细节,掌握这些技巧后,不管是做搜索、
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。