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前端网发表,如需转载,请注明页面地址。
code前端网


发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。