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

一、Vue3 Router 传参有哪几种核心方式?

terry 2周前 (10-02) 阅读数 50 #Vue

不少刚开始折腾Vue3项目的同学,一碰到页面跳转传参就发懵:到底有多少种传参方式?不同场景选哪种更稳?参数刷新没了咋救?这篇用问答形式,把Vue3 Router传参的关键知识点、实操技巧和避坑点全唠明白,从基础到细节一次吃透~

Vue3 Router 传参方式主要围绕「路由配置」和「跳转时的参数携带」展开,常见的有这四类:

动态路由参数(路径参数)

把参数直接嵌在路由路径里,/user/:id 这种格式,配置路由时用 :参数名 占坑,跳转时把具体值填进去, url 里就会显示成 /user/123

params 传参(命名路由的隐式参数)

通过命名路由的 params 字段传参,但只有和动态路由参数匹配的部分才会显式出现在 url;如果路由没配置对应路径参数,这些 params 属于“内存级”参数,刷新页面会丢失。

query 传参(查询参数)

参数跟在 url 的 后面,像 /user?tab=info&page=2 这样,不管路由咋配置,只要跳转时带 query ,参数就会明文出现在 url 里,刷新也不会丢。

props 传参(路由组件解耦方案)

通过路由配置的 props 选项,把路由参数“转成”组件的 props 传入,组件不用直接依赖 useRoute() ,更方便复用和测试。

动态路由参数咋用?适合啥场景?

动态路由参数是“把参数写进 url 路径”的玩法,步骤分两步:配置路由 + 跳转传参 + 接收参数。

配置路由(占坑)

在路由规则里,用 :参数名 定义动态段,

const routes = [
  { 
    path: '/user/:id',  // id 是动态参数
    name: 'User', 
    component: () => import('./views/User.vue') 
  }
]

跳转时传参(填坑)

可以用编程式导航或者声明式导航

  • 编程式(用 router.push ):
    import { useRouter } from 'vue-router'
    const router = useRouter()
    router.push({ name: 'User', params: { id: 123 } }) 
    // 或者直接拼路径:router.push('/user/123')
  • 声明式(用 <RouterLink> ):
    <RouterLink :to="{ name: 'User', params: { id: 123 } }">去用户页</RouterLink>
    <!-- 或者 <RouterLink to="/user/123">去用户页</RouterLink> -->

组件内接收参数

useRoute() 钩子拿参数:

<script setup>
import { useRoute } from 'vue-router'
const route = useRoute()
const userId = route.params.id  // 这里的 id 和路由配置里 :id 对应
</script>

适合啥场景?

  • 页面唯一性强:比如用户详情、商品详情,每个 id 对应唯一页面, url 里带 id 也方便用户收藏/分享。
  • SEO 需求:搜索引擎更易抓取带参数的静态路径(/user/123?id=123 更像静态页)。

query 传参和 params 传参有啥区别?

很多同学分不清这俩,核心差异在「参数是否显式在 url」和「刷新是否保留」上,具体看这张对比表:

维度 query 传参 params 传参(非动态路由场景)
url 显示 明文显示在 后(如 ?tab=info 不在 url 显示(仅内存中临时保存)
刷新保留 刷新后参数还在 刷新后参数丢失(因为没存在 url 里)
路由配置依赖 不需要路由配置提前占坑 若想参数显式在 url,必须配动态路由
使用灵活性 适合临时筛选、分页等可变参数 适合和动态路由绑定的“页面核心标识”

举个栗子🌰

做电商商品列表,筛选条件(比如价格区间、分类)适合用 query :因为用户刷新页面后,筛选条件得保留,而且不需要“收藏筛选后的 url”时,用 query 灵活;
订单详情页,订单 id 是页面核心标识,适合用动态路由参数(属于 params 里和路径绑定的部分),保证 url 里有 id ,刷新也能拿到。

用 props 咋给路由组件传参?

路由组件直接用 `useRoute()` 拿参数,会让组件和路由强耦合(比如复用组件时,得先配路由),用 `props` 传参能解耦,让组件更“纯粹”。

路由配置里开 props: true

当路由是动态路由(如 /user/:id ),把 props 设为 true ,路由的 params 会自动变成组件的 props:

路由配置:

{ 
  path: '/user/:id', 
  name: 'User', 
  component: User, 
  props: true  // 关键配置
}

组件里接收:

<script setup>
defineProps(['id'])  // 直接用 props 接收,不用 useRoute 了
console.log(id)  // 能拿到路由里的 :id 参数
</script>

传静态 props(少用,但得知道)

props 设为对象,不管路由参数是啥,组件都拿静态值:

{ 
  path: '/user', 
  component: User, 
  props: { tab: 'info' }  // 组件拿到的 tab 固定是 'info'
}

函数式 props(动态逻辑传参)

props 可以是函数,根据 route 对象返回动态值,适合复杂场景:

{ 
  path: '/user/:id', 
  component: User, 
  props: (route) => { 
    return { 
      id: route.params.id, 
      defaultTab: 'info'  // 额外加静态值
    } 
  }
}

组件接收:

<script setup>
defineProps(['id', 'defaultTab'])
</script>

为啥推荐用 props?

  • 解耦路由依赖:组件不用关心“我是不是路由组件”,复用的时候直接传 props 就行。
  • 测试更简单:写单元测试时,不用模拟路由,直接传 props 就能测。

编程式导航和声明式导航传参有啥不同?

Vue3 里跳转页面分「编程式(用 JS 逻辑跳)」和「声明式(用 组件跳)」,传参逻辑一样,但使用场景不同。

编程式导航(router.push / router.replace 等)

适合有逻辑判断后再跳转的场景,比如点击按钮后,先调接口存数据,再跳页面:

import { useRouter } from 'vue-router'
const router = useRouter()
const handleClick = async () => {
  await saveData()  // 调接口存数据
  router.push({ 
    name: 'Success', 
    query: { msg: '保存成功' } 
  })
}

声明式导航(

适合页面上的静态链接,比如导航栏、菜单:

<RouterLink 
  :to="{ 
    name: 'Article', 
    params: { id: 456 }, 
    query: { from: 'home' } 
  }"
>
  看文章
</RouterLink>

核心区别

  • 编程式是逻辑里的动态跳转,能结合异步操作、条件判断;
  • 声明式是模板里的静态跳转,更直观,适合用户能直接点的链接。

传参后刷新页面,参数丢了咋解决?

碰到“跳转时参数有值,刷新页面就没了”,十有八九是「params 传参没和动态路由绑定」导致的。

问题根源

如果用 params 传参,但路由没配置对应的动态路径参数,这些 params 只存在内存里,刷新页面时,路由重新初始化,内存里的参数就没了。

比如错误示范:
路由配置是 path: '/user' (没配 :id ),但跳转时传 params: { id: 123 }id 不会出现在 url ,刷新就丢。

解决方法

根据需求选方案:

  1. 需要参数刷新保留 → 用 query 传参
    把参数放到 query 里,不管路由咋配,query 会明文存在 url ,刷新不丢:

    router.push({ name: 'User', query: { id: 123 } }) 
    // url 变成 /user?id=123 ,刷新后 route.query.id 还在
  2. 参数是页面核心标识 → 用动态路由参数
    把参数写到路由路径里(配 :id ),这样参数既在 url 里,刷新也能拿到:

    // 路由配置
    { path: '/user/:id', ... }
    // 跳转
    router.push({ name: 'User', params: { id: 123 } }) 
    // url 是 /user/123 ,刷新后 route.params.id 还在
  3. 临时参数,刷新丢了也没事 → 继续用 params(但得接受刷新丢失)
    如果参数是临时用的(比如表单跳转前的临时状态),丢了也不影响,那继续用 params 传参就行,不用改。

多参数传递时,怎么组织更清晰?

页面跳转时,经常要传多个参数(id、类型、筛选条件),乱传容易搞混,得按“参数重要性 + 场景”分类传。

分类传参逻辑

  • 核心标识参数(如用户 id、商品 id):用动态路由参数,写进 url 路径,保证刷新不丢,且页面唯一性强。
  • 可变筛选参数(如分页、tab 切换、搜索关键词):用query 传参,明文在 url ,刷新保留,还能让用户通过 url 分享筛选状态。
  • 临时逻辑参数(如是否弹窗、临时标记):用params 传参(非动态路由场景),但要接受刷新丢失。

举个综合栗子🌰

做一个“商品详情 + 评论 tab + 分页”的页面:

  • 商品 id 是核心 → 动态路由:path: '/product/:id'
  • tab(是看详情还是评论)、分页 page → query 传参:query: { tab: 'comment', page: 2 }
  • 临时标记(比如是否自动展开评论)→ params 传参(非动态路由,刷新丢了也没事)

跳转代码:

router.push({ 
  name: 'Product', 
  params: { id: 789 },  // 动态路由参数
  query: { tab: 'comment', page: 2 },  // 筛选参数
  params: { autoOpen: true }  // 临时参数(注意:这里如果路由没配 :autoOpen,刷新会丢)
})

这样分类后,参数用途清晰,维护起来也方便~

Vue3 组合式 API 里,咋获取路由参数?

Vue3 的 <script setup> 语法里,获取路由参数得用 `useRoute()` 钩子,步骤很简单:

导入并调用 useRoute

<script setup>
import { useRoute } from 'vue-router'
const route = useRoute()  // 拿到当前路由对象
</script>

取 params 或 query

  • 取动态路由参数 / params :route.params.参数名
  • 取 query 参数:route.query.参数名

示例(承接动态路由例子):

<template>
  <div>用户ID:{{ userId }}</div>
  <div>当前标签:{{ activeTab }}</div>
</template>
<script setup>
import { useRoute } from 'vue-router'
const route = useRoute()
const userId = route.params.id  // 动态路由参数
const activeTab = route.query.tab  // query 参数
</script>

注意点

useRoute() 必须在组合式 API 上下文里用(<script setup>setup() 函数里),不能在普通函数、生命周期钩子外乱用,否则拿不到路由对象~

传参时容易踩的坑,咋避?

最后聊聊踩坑经验,提前避坑少掉头发~

坑1:params 传参没配动态路由,刷新丢参数

→ 解决:核心参数用动态路由或 query;临时参数接受丢失,或者转成 query。

坑2:路由配置了动态参数,但跳转时没传,页面崩了

→ 解决:跳转前做参数校验,或者路由配置里给动态参数设默认(path: '/user/:id?' 加问号表示可选)。

坑3:用了 props: true ,但组件没定义对应 props

→ 解决:组件里用 defineProps 声明接收的参数,defineProps(['id'])

坑4:编程式导航用 path 跳转时,传 params 不生效

→ 原因:用 path 跳转时,params 会被忽略(因为 path 是静态字符串,没法绑定 params)。
→ 解决:要么用 name + params 跳转,要么把参数拼到 path 里(如 /user/123 )。

把这些传参方式、场景、避坑点理清楚后,Vue3 页面跳转传参就不再是玄学啦~下次写项目时,先想清楚参数的“重要性”和“是否要刷新保留”,再选对应的传参方式,代码逻辑会清爽很多~如果还有细节没搞懂,评论区随时喊我~

版权声明

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

发表评论:

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

热门