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

Vue Router里怎么玩Query Params?常见问题一次说清

terry 8小时前 阅读数 10 #Vue

做Vue项目时,路由传参是绕不开的需求,尤其是带筛选条件、分页信息这类场景,Query Params(查询参数)特别实用,但刚接触Vue Router时,很多同学会纠结“怎么传query?怎么拿?改了不跳转咋办?”这类问题,这篇用问答形式把Vue Router和Query Params的常见问题拆明白,新手也能快速上手~

Query Params是啥?和动态路由参数有啥区别?

先搞清楚概念:Query Params是URL里「?」后面的键值对,/products?category=phone&page=2 里的 categorypage 就是Query Params,它的特点是“可选”“不影响路由匹配”——哪怕query变了,只要路径(比如/products)不变,路由还是匹配同一个组件。

而动态路由参数是路径里的变量/user/:id 里的 :id ,它是路由规则的一部分,必须和路径严格对应(比如/user/123 匹配,user/abc 可能404),而且动态参数变化时,默认会销毁重建组件(除非配置 keep-alive 或处理组件复用)。

举个场景例子:

  • 用动态参数:用户个人页 /user/123 ,每个用户ID对应唯一路径,适合“唯一资源页”。
  • 用Query Params:商品列表页 /products?sort=price ,排序方式变了但路径还是/products,适合“同一页面的不同状态”。

怎么用Vue Router传递Query Params?

Vue Router传query分「声明式导航」<router-link>)和「编程式导航」router.push/replace)两种方式,核心是给 to 对象传 query 属性。

声明式导航(<router-link>

在模板里用绑定 to 的对象语法:

<router-link 
  :to="{ 
    path: '/products', 
    query: { category: 'laptop', page: 1 } 
  }"
>
  跳转到笔记本列表
</router-link>

点击后URL会变成 /products?category=laptop&page=1

编程式导航(router.push/replace

在逻辑里用路由实例的方法,比如用户点击按钮触发筛选:

<script setup>
import { useRouter } from 'vue-router';
const router = useRouter();
// 跳转并传query
const handleFilter = () => {
  router.push({
    path: '/products',
    query: { category: 'phone', sort: 'sales' }
  });
};
</script>

如果想替换当前历史记录(比如不想让用户回退到之前的状态),把 push 换成 replace 就行。

⚠️ 注意:Query Params本质是字符串,传对象/数组要手动处理!比如想传筛选条件对象,得先 JSON.stringify ,接收时再 JSON.parse

// 传的时候
router.push({
  query: { 
    filters: JSON.stringify({ price: [100, 200], brand: ['huawei'] }) 
  }
});
// 接收的时候
const route = useRoute();
const filters = JSON.parse(route.query.filters);

页面里怎么接收Query Params?

接收分“初始化时读取”“参数变化时响应”两种情况,因为Vue Router的组件可能会复用(同一路径不同query时,组件不销毁),所以要注意监听变化。

初始化时读取

useRoute 钩子拿到当前路由对象,直接取 query 属性:

<script setup>
import { useRoute } from 'vue-router';
const route = useRoute();
// 组件挂载时读取query
onMounted(() => {
  console.log('当前分类:', route.query.category); // 比如取?category的值
  console.log('当前页码:', route.query.page);
});
</script>

监听Query变化

当同一路径下query变化时(比如从 ?page=1 变到 ?page=2 ),组件不会重新挂载,所以要用 watch 监听 route.query

<script setup>
import { useRoute, watch } from 'vue-router';
const route = useRoute();
watch(
  () => route.query, 
  (newQuery, oldQuery) => {
    console.log('query变了!新参数:', newQuery);
    // 比如根据新的page参数重新请求列表数据
    fetchProducts(newQuery.page);
  }, 
  { immediate: true } // 初始化时也执行一次
);
</script>

想改Query参数但不“跳转页面”,能实现吗?

很多同学误以为“改query必须跳转到新页面”,其实只要调用router.push/replace,哪怕路径不变,也会触发路由更新(URL的query变化,组件内的route.query也会更新)。

比如当前URL是 /products?page=1 ,想改成 ?page=2 ,直接调:

router.push({ query: { page: 2 } });

这样URL会变成 /products?page=2 ,同时组件内的 route.query 也会同步更新(如果用了watch监听,就能响应)。

要是不想新增历史记录(比如筛选组件的“重置”按钮,只想替换当前状态),用 router.replace

router.replace({ query: { page: 1, category: 'all' } });

Query Params和路由守卫怎么配合?

路由守卫(比如全局守卫、组件内守卫)可以用来校验query合法性处理权限,举几个常用场景:

全局守卫(beforeEach)校验参数

比如商品列表页要求 page 必须是数字,否则跳转到第1页:

// router/index.js
const router = createRouter({ ... });
router.beforeEach((to, from, next) => {
  if (to.path === '/products') {
    const page = to.query.page;
    // 检查page是否是有效数字
    if (page && isNaN(Number(page))) {
      // 无效则强制设为1
      next({ query: { ...to.query, page: 1 } });
    } else {
      next();
    }
  } else {
    next();
  }
});

组件内守卫(beforeRouteUpdate)响应参数变化

当组件复用(同路径不同query)时,用 beforeRouteUpdate 提前处理参数:

<script>
export default {
  // 组件内守卫,路由更新前触发(query变化时会触发)
  beforeRouteUpdate(to, from, next) {
    // 根据新的query重新请求数据
    this.fetchData(to.query.category);
    next();
  }
}
</script>

复杂场景咋玩?比如多条件筛选、跨页面保留参数

实际开发中,Query Params最常用的场景是“页面状态持久化”(比如筛选、分页、排序)和“跨页面传参”,分享两个典型案例:

案例1:商品列表多条件筛选(状态持久化)

需求:用户选分类、价格区间、排序方式,刷新页面后筛选条件不丢,URL能分享。

实现思路:把所有筛选条件存在Query Params里,组件初始化时从query读状态,变化时更新query。

代码简化版:

<template>
  <div class="filters">
    <select v-model="filters.category">
      <option value="all">全部</option>
      <option value="phone">手机</option>
      <option value="laptop">笔记本</option>
    </select>
    <button @click="filters.price = '0-500'">低价</button>
    <button @click="filters.price = '500-2000'">中价</button>
    <select v-model="filters.sort">
      <option value="default">默认排序</option>
      <option value="sales">销量优先</option>
      <option value="price">价格从低到高</option>
    </select>
  </div>
</template>
<script setup>
import { useRoute, useRouter, watch, reactive } from 'vue-router';
const route = useRoute();
const router = useRouter();
// 初始化筛选条件:从query里拿,没有则设默认
const filters = reactive({
  category: route.query.category || 'all',
  price: route.query.price || '0-∞',
  sort: route.query.sort || 'default'
});
// 监听filters变化,同步到query
watch(filters, (newFilters) => {
  router.push({ query: newFilters });
}, { deep: true });
// 根据filters请求数据(省略具体请求逻辑)
const fetchProducts = () => {
  // 用filters里的参数发请求
};
onMounted(fetchProducts);
watch(filters, fetchProducts, { deep: true });
</script>

案例2:跨页面保留筛选参数(比如列表→详情→返回列表)

需求:从商品列表(带筛选query)进入详情页,返回列表时保留之前的筛选条件。

实现思路:进入详情页时,把列表页的query存在详情页的query里,返回时自然携带。

列表页跳转代码:

// 列表页点击商品进入详情
const goToDetail = (productId) => {
  const { query } = useRoute();
  router.push({
    path: `/detail/${productId}`,
    query: { ...query } // 把列表页的query全带到详情页
  });
};

详情页返回代码(用router.back()):

<template>
  <button @click="goBack">返回列表</button>
</template>
<script setup>
import { useRouter } from 'vue-router';
const router = useRouter();
const goBack = () => {
  router.back(); // 历史记录回退,自动带之前的query
};
</script>

踩坑:Query Params的类型、SEO咋处理?

实际开发还有些细节容易踩坑,集中解答:

坑1:Query参数的类型丢失(数字、布尔值变字符串)

因为URL里的Query Params本质是字符串,所以传数字、布尔值会被自动转成字符串,比如传 { page: 2 } ,URL里是 ?page=2 ,但 route.query.page 拿到的是字符串 "2"

解决方法:接收时手动转类型

const page = Number(route.query.page) || 1; // 转数字,默认1
const isSale = route.query.isSale === 'true'; // 转布尔值

坑2:Query Params太多导致URL过长

如果传复杂对象(比如多层筛选条件),用 JSON.stringify 会让URL特别长,甚至超过浏览器限制。

解决思路:只传关键标识,而非完整数据,比如筛选条件存在Vuex/Pinia里,Query只传筛选的ID;或者后端提供“筛选配置ID”,前端存ID到query,再根据ID拉配置。

坑3:SEO不友好(SPA页面爬取不到Query参数内容)

纯SPA(单页应用)的SEO天生弱,因为搜索引擎爬取时可能不执行JS,导致带Query的页面内容被忽略。

解决方法:

  • 服务端渲染(SSR)(比如Nuxt.js),让服务端根据Query参数渲染出完整HTML,方便爬虫抓取。
  • 给Query参数起语义化的键名category=electronicsc=1 友好),配合Meta标签优化。

看完这些问题,是不是对Vue Router的Query Params更有数了?总结一下核心:Query是“挂在URL问号后、不影响路由匹配、用来存页面状态”的参数,传参用`to`对象的`query`属性,接收用`useRoute().query`,变化时要监听,实际项目里多结合筛选、分页这类场景练手,很快就能熟练~要是还有啥细节没搞懂,评论区随时聊~

版权声明

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

发表评论:

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

热门