Code前端首页关于Code前端联系我们

Vue Router 怎么获取 query 参数?从基础到实战一次讲透

terry 2小时前 阅读数 5 #Vue

在做 Vue 项目时,经常需要在页面跳转时传递参数,比如搜索关键词、分页页码、标签切换标识这些信息,Vue Router 里的 query 参数就是专门用来处理这类“带在 URL 上的可选参数”的,但刚接触的同学可能会疑惑:怎么在组件里拿到这些 query 参数?路由守卫里怎么获取?不同场景下有啥要注意的?今天就从基础到实战,把 Vue Router 获取 query 参数的门道一次性讲清楚~

先搞懂 Vue Router 里的 query 是啥?

很多同学会把 query 和 params 搞混,得先把概念理清楚。query 参数是跟在 URL “?” 后面的键值对,http://xxx.com/page?keyword=vue&page=2 里,keywordpage query 参数,它有两个特点:

  • 「可选性」:就算路由配置里没声明,也能传;
  • 「刷新不丢」:页面刷新后,URL 里的 query 还在,参数不会消失。

params 参数是嵌在路由路径里的(path: '/user/:id'),必须在路由配置中预先定义,而且刷新时如果路由配置没保留 params 规则,参数可能丢失,所以如果是“可选的、想暴露在 URL 上方便分享”的参数,优先用 query~

组件内怎么拿 query 参数?(分 Vue2 和 Vue3 讲)

项目里用的 Vue 版本不同,获取方式略有区别,但核心逻辑一致:通过路由实例上的 query 属性获取。

情况 1:Vue3 + 组合式 API(最常见的现代写法)

Vue3 推荐用组合式 API,配合 useRoute 函数来拿路由信息,步骤很简单:

  1. 先从 vue-router 里导入 useRoute
  2. 调用 useRoute() 拿到当前路由实例;
  3. 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?

路由守卫是控制页面跳转权限、做埋点、参数处理的常用手段,不管是全局守卫、路由独享守卫,还是组件内守卫,都能通过 tofrom 参数拿到 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 的 onBeforeRouteUpdateonBeforeRouteLeave,用法类似:

<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 完美解决~

步骤拆解

  1. 搜索输入框绑定 v-modelkeyword
  2. 点击搜索按钮时,用 router.pushquery: { keyword } 跳转到自身路由(同路由跳转);
  3. 组件创建/更新时,从 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 参数是 nullundefined

比如跳转时没传某个参数,或者路由配置有问题,导致 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前端网发表,如需转载,请注明页面地址。

发表评论:

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

热门