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

Vue Router怎么添加查询参数?从基础到进阶实操全解析

terry 3周前 (09-04) 阅读数 40 #Vue

咱在做Vue项目时,经常碰到要在路由里带查询参数的情况——比如列表页筛选条件得保留、详情页传参后刷新还得能接着用…这时候就得靠Vue Router的query参数啦!但新手刚上手,可能连query咋加、不同场景咋用、参数丢了咋解决都摸不着头脑,这篇从基础用法到进阶技巧,一步步给你讲透~

先搞懂:Vue Router里的query参数是干啥的?

简单说,query参数就是URL里后面跟着的键值对(比如/page?keyword=手机&page=2里的keywordpage),它主要用来干这两件事:

  • 传递“非必须但要保留”的信息:像列表页的筛选条件(分类、价格范围)、搜索关键词,用户刷新页面或分享链接时,这些条件还能生效;
  • 和路由参数(params)打配合:params是路由路径里的动态段(比如/user/:id里的:id),适合传“必须的标识”;query更灵活,适合传“临时筛选、分页”这类信息。

关键区别得记牢:

  • query参数刷新页面不会丢(因为在URL里明明白白写着);
  • params参数如果路由配置里没写动态段(比如/user而不是/user/:id),刷新就没了!

基础操作:两种导航方式咋加query?

Vue Router里导航分声明式(用<router-link>)和编程式(用this.$router.push这类方法),加query的逻辑差不多,但写法有区别~

声明式导航:<router-link>里加query

:to绑定一个对象,里面放name(或path)和query,举个电商列表页的例子:

<router-link 
  :to="{ 
    name: 'ProductList', // 路由的“命名”,比path更稳(路由path改了也不用全改)
    query: { 
      category: 'electronics', // 分类:电子产品
      priceRange: '0-500'       // 价格区间
    } 
  }"
>去电子产品列表</router-link>

点完后,URL会变成/product/list?category=electronics&priceRange=0-500(假设ProductList的path是/product/list)。

⚠️ 小提醒:用path也能传,但更推荐name!因为路由配置可能变(比如path改了),用name能自动匹配,减少维护成本~

编程式导航:router.push/router.replace里加query

在方法里调用this.$router.push()(或replace),传一个包含namequery的对象,比如列表页切换排序方式:

export default {
  methods: {
    handleSort() {
      this.$router.push({
        name: 'ProductList',
        query: { sort: 'salesDesc' } // 按销量降序
      })
    }
  }
}
  • push:往历史记录里新增一条,用户点返回会回到上一个状态;
  • replace替换当前历史记录,适合“筛选条件切换不需要回退”的场景(比如列表页换筛选,回退时直接跳过筛选步骤)。

要是想在当前页面更新query但不跳转(比如筛选条件变化时),可以这么玩:

// 合并旧query,只改sort
this.$router.push({
  name: this.$route.name, // 保持当前路由名
  query: { ...this.$route.query, sort: 'priceAsc' }
})

这样页面不会整体刷新,但query变了后,组件里监听$route变化就能更新数据~

不同场景下的query处理技巧

光会基础用法不够,实际项目里场景五花八门,得针对性处理!

列表页筛选条件:刷新/分享后还能生效

比如电商列表页,用户选了“分类=手机、价格=0-3000、排序=销量”,这些条件得存在URL里,步骤如下:

  • 初始化:组件创建时,从$route.query里拿参数,给筛选表单赋值;
  • 更新:筛选表单变化时,用router.push更新query;
  • 防重复请求:用防抖(debounce)避免用户频繁操作触发太多请求。

代码示例:

import { debounce } from 'lodash' // 引入防抖工具
export default {
  data() {
    return {
      filterForm: { category: '', price: '', sort: '' },
      debounceUpdate: null // 防抖函数实例
    }
  },
  created() {
    // 从query初始化表单
    this.filterForm = { ...this.filterForm, ...this.$route.query }
    // 初始化防抖:300毫秒后再更新query
    this.debounceUpdate = debounce((newVal) => {
      this.$router.push({
        name: this.$route.name,
        query: newVal
      })
    }, 300)
  },
  watch: {
    // 深度监听表单变化
    'filterForm': {
      deep: true,
      handler(newVal) {
        this.debounceUpdate(newVal)
      }
    }
  }
}

这样用户快速切换筛选时,不会疯狂发请求,体验更丝滑~

详情页传参:刷新后还能拿到数据

比如商品详情页,用商品ID当query参数(也能用params,但query更灵活),核心是监听$route.query变化(因为同一组件内跳转,created只执行一次)。

路由配置(不需要动态段):

{
  path: '/product/detail',
  name: 'ProductDetail',
  component: ProductDetail
}

跳转时(比如列表页点商品):

<router-link :to="{ name: 'ProductDetail', query: { id: 123 }}">去详情</router-link>

详情页里拿ID并请求数据:

export default {
  data() { return { productId: '' } },
  created() {
    this.productId = this.$route.query.id
    this.fetchDetail()
  },
  watch: {
    // 同一组件内跳转到其他商品(比如推荐栏),监听query变化
    '$route.query.id'(newId) {
      this.productId = newId
      this.fetchDetail()
    }
  },
  methods: {
    fetchDetail() {
      // 用productId发请求拿详情
    }
  }
}

多参数组合与清空:比如搜索页

搜索页可能有“关键词、分类、页码”多个参数,要支持清空某个参数(比如清空分类),直接传undefined会让URL出现category=undefined,得用delete干净删除:

// 假设当前query是 { keyword: '手机', category: 'apple', page: 2 }
// 清空category
const newQuery = { ...this.$route.query }
delete newQuery.category // 删除category属性
this.$router.push({
  name: 'Search',
  query: newQuery
})

这样URL里的category就没了,页面也会更新~

常见问题 & 避坑指南

用query时总会碰到些“玄学问题”,提前避坑少踩雷!

query参数刷新后没了?

十有八九是把query写成params了!再强调一次:

  • params是路由路径里的动态段(如/user/:id),适合传“必须的标识”;
  • query是URL里后的参数,适合传“临时筛选、分页”。

错误示范(刷新后params丢了):

this.$router.push({
  name: 'User',
  params: { id: 123 } // 路由配置是path: '/user'(没有:id),刷新就没了!
})

正确示范(用query,刷新还在):

this.$router.push({
  name: 'User',
  query: { id: 123 }
})

同一个路由,query更新了但页面没反应?

Vue Router默认判断“目标路由和当前路由一样”(比如name相同、path相同),就不触发组件更新,解决办法有两个:

  • <router-link>key,强制让Vue认为是新元素:
<router-link 
  :to="{ name: 'SamePage', query: { tab: 'info' }}"
  :key="JSON.stringify({ name: 'SamePage', query: { tab: 'info' } })"
>信息页</router-link>
  • 组件内监听$route.query变化,手动更新数据:
watch: {
  '$route.query'(newQuery) {
    // 根据newQuery更新组件数据
  }
}

query里的中文/特殊字符咋处理?

不用慌!Vue Router会自动对query参数做URL编码(比如中文“手机”会变成%E6%89%8B%E6%9C%BA),获取时又会自动解码成中文,所以不用手动编码解码,框架帮咱搞定了~

query参数类型不对?(比如数字变字符串)

URL里的参数都是字符串,所以this.$route.query.id拿到的是'123'(哪怕你传的是数字123),如果接口要数字,得手动转:

const productId = Number(this.$route.query.id)
if (!isNaN(productId)) {
  // 有效数字,发请求
}

进阶玩法:query和路由设计深度结合

掌握基础后,还能玩点高级操作,让路由传参更丝滑~

结合路由元信息(meta):登录后跳回原页面

有些页面要登录才能进(比如订单页),用户没登录时,得先跳登录页,登录后再跳回带query的原页面,用meta标记需要登录的页面,再在全局守卫里处理:

路由配置:

{
  path: '/order',
  name: 'OrderList',
  component: OrderList,
  meta: { requiresAuth: true } // 需要登录
}

全局前置守卫(router.beforeEach):

router.beforeEach((to, from, next) => {
  if (to.meta.requiresAuth && !isLogin()) { // isLogin()判断是否登录
    // 把目标路由的信息(含query)存起来
    store.commit('setRedirectRoute', {
      path: to.path,
      name: to.name,
      query: to.query
    })
    next({ name: 'Login' }) // 跳登录页
  } else {
    next()
  }
})

登录成功后,跳回原页面:

const redirectRoute = store.state.redirectRoute
this.$router.push({
  name: redirectRoute.name,
  query: redirectRoute.query
})

动态生成复杂query:比如后台多筛选项

后台管理系统的表格,可能有“日期范围、状态、关键词”等一堆筛选项,可以把筛选项封装成对象,直接传给query:

// 筛选条件对象
const filters = {
  startDate: '2024-01-01',
  endDate: '2024-02-01',
  status: 'pending',
  keyword: '订单'
}
// 跳转并传参
this.$router.push({
  name: 'OrderList',
  query: filters
})

组件内直接从$route.query里拿参数,还能写个工具函数处理空值、格式化日期,让代码更简洁~

服务端渲染(SSR)下的query处理(以Nuxt.js为例)

在Nuxt.js这类SSR框架里,服务端和客户端都要能拿到query,可以在asyncData里取query发请求:

export default {
  async asyncData({ route }) { // 服务端没有this,从上下文拿route
    const { query } = route
    const data = await fetchData(query) // 根据query请求数据
    return { data }
  }
}

客户端导航时,asyncData也会触发,保证前后端数据一致~

掌握query,让路由传参更灵活

Vue Router的query参数,是页面间传递“临时信息”“保留用户操作”的神器,从基础的声明式/编程式导航加query,到列表筛选、详情传参的场景化处理,再到避坑和进阶玩法,核心是理解query的特性(URL可见、刷新保留),结合组件生命周期和路由守卫来管理参数变化。

实际项目里,多想想“哪些信息需要在URL里可见、能分享”——这类信息就适合用query;像用户ID这种“必须的路由标识”,用params配合路由配置更合适,遇到问题时,先检查路由配置、跳转方式、参数类型,大部分坑都能绕开~

现在再回头看,是不是对query参数的用法清晰多了?下次写项目时,就知道啥场景用啥方法,再也不担心参数丢了、页面不更新啦~

(全文约2200字,涵盖基础、场景、问题、进阶,从入门到实践一网打尽~)

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

发表评论:

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

热门