Vue2 和 Vue3 中 Router props 配置详解:彻底摆脱 $route 依赖

作者:袖梨 2026-07-09

为什么需要 Router props

先看一段"经典"代码:

Vue2 & Vue3 中 Router `props` 配置详解:彻底摆脱 `$route` 依赖

 复制代码<template>
  <div>用户ID:{{ $route.params.id }}</div>
</template>

这有什么问题?组件强依赖 $route,导致:

  • 组件难以测试——必须模拟路由对象
  • 组件难以复用——换个场景就得提供 $route
  • 代码不够直观——参数传递链路不清晰

Router props 就是来解决这个痛点的——它让路由参数以组件 props 的形式注入,组件完全感知不到路由的存在。


Vue Router 3(Vue2)中的 props 配置

Vue Router 3.x 在路由声明中添加了 props 字段,支持 3 种模式

布尔模式 —— props: true

$route.params 自动映射为组件 props,简单粗暴

 复制代码// router/index.js
const routes = [
  {
    path: '/user/:id',
    component: User,
    props: true   //  将 params.id 映射为 props.id
  }
]
 复制代码<!-- User.vue -->
<template>
  <div>用户ID:{{ id }}</div>
</template><script>
export default {
  props: ['id']
}
</script>

对象模式 —— props: { ... }

传递静态数据,与路由参数无关:

 复制代码{
  path: '/promotion',
  component: Promotion,
  props: { banner: 'summer_sale.jpg' }
}

适用场景: 配置化组件、A/B 测试、功能开关控制。

函数模式 —— props: (route) => ({ ... })

最灵活的模式,可以自由组合 paramsquery 甚至自定义逻辑:

 复制代码{
  path: '/search',
  component: SearchResult,
  props: (route) => ({
    keyword: route.query.q,
    page: Number(route.query.page) || 1,
    from: 'search'           // 可注入静态数据
  })
}
 复制代码<!-- SearchResult.vue -->
<script>
export default {
  props: {
    keyword: { type: String, default: '' },
    page:    { type: Number, default: 1 },
    from:    { type: String }
  }
}
</script>

Vue Router 4(Vue3)中的 props 配置

好消息:Vue Router 4 的 props API 与 Vue Router 3 完全兼容,上手零成本。

三种模式示例(Vue3 Composition API)

 复制代码import { createRouter, createWebHistory } from 'vue-router'const routes = [
  // 布尔模式
  {
    path: '/user/:id',
    component: () => import('@/views/User.vue'),
    props: true
  },
  // 对象模式
  {
    path: '/about',
    component: () => import('@/views/About.vue'),
    props: { title: '关于我们' }
  },
  // 函数模式
  {
    path: '/products',
    component: () => import('@/views/Products.vue'),
    props: (route) => ({
      category: route.query.category || 'all',
      sort: route.query.sort || 'default'
    })
  }
]export default createRouter({
  history: createWebHistory(),
  routes
})
 复制代码<!-- User.vue(Vue3) -->
<script setup>
defineProps({
  id: String
})
</script><template>
  <div>用户ID:{{ id }}</div>
</template>

命名视图的 props

路由有多个命名视图时,可以为每个视图单独设置 props

 复制代码{
  path: '/dashboard/:id',
  components: {
    default: Dashboard,
    sidebar: Sidebar,
    header: HeaderNav
  },
  props: {
    default: true,               // 将 params.id 传给 Dashboard
    sidebar: (route) => ({       // 函数模式
      menu: route.query.menu || 'main'
    }),
    header: { title: '控制台' }   // 静态数据
  }
}

嵌套路由的 props 传递

 复制代码{
  path: '/user/:userId',
  component: UserLayout,
  props: true,  // userId 传给 UserLayout
  children: [
    {
      path: 'profile',
      component: UserProfile,
      props: true  // userId 也传给 UserProfile
    },
    {
      path: 'posts',
      component: UserPosts,
      props: (route) => ({
        userId: route.params.userId,  // 父级参数需要手动传递
        page: Number(route.query.page) || 1
      })
    }
  ]
}

Vue2 vs Vue3 对比一览

特性Vue Router 3(Vue2)Vue Router 4(Vue3)
布尔模式 映射 params 映射 params
对象模式 静态数据 静态数据
函数模式 灵活组合 灵活组合
命名视图 props 支持 支持
嵌套路由自动透传 不会 不会
TypeScript 推导️ 较弱 强类型推导
Composition API Options API defineProps

实际场景对比

不用的糟糕写法

 复制代码<template>
  <div>
    <h1>{{ $route.params.id }} 的文章</h1>
    <p>分类:{{ $route.query.category }}</p>
  </div>
</template><script>
export default {
  mounted() {
    this.fetchData(this.$route.params.id)
  },
  methods: {
    fetchData(id) { /* 模拟请求 */ }
  }
}
</script>

三个问题: 耦合 $route、无法复用、难以测试。

使用 props 的最佳实践

 复制代码// 路由配置
{
  path: '/user/:id/articles',
  component: UserArticles,
  props: (route) => ({
    userId: route.params.id,
    category: route.query.category || 'all'
  })
}
 复制代码<!-- UserArticles.vue(Vue3) -->
<script setup>
defineProps({
  userId:   { type: String, required: true },
  category: { type: String, default: 'all' }
})
// 直接使用 props,与路由完全解耦
</script>

三大优势:

  • 组件纯组件化——传入什么渲染什么
  • 单元测试只需 mount(Component, { props }),无需模拟路由
  • 可在任何地方复用该组件

函数模式进阶用法

参数类型转换

 复制代码props: (route) => ({
  id: Number(route.params.id),   // 字符串 → 数字
  page: parseInt(route.query.page) || 1,
  tags: route.query.tags ? route.query.tags.split(',') : []
})

路由级权限控制

 复制代码props: (route) => ({
  permission: route.meta.requiredPermission || 'guest',
  role: route.meta.role
})

合并多个来源

 复制代码props: (route) => ({
  ...route.params,
  ...route.query,
  from: 'router',
  timestamp: Date.now()
})

默认值与兜底

 复制代码props: (route) => {
  const { id, tab = 'overview' } = route.params
  return {
    id: id || 'default',
    tab,
    query: route.query
  }
}

总结:一句话记住

模式适用场景
props: true简单场景,只需 params
props: { ... }传递不变静态配置
props: (route) => ({ ... })复杂场景,需要组合参数

最佳实践建议: 在新项目中对所有带路由参数的组件统一使用 props 配置,养成"路由只管路由,组件只管 props"的习惯。这对长期维护和团队协作有百利而无一害。


实战小贴士

如果你正在从 Vue2 迁移到 Vue3,props 配置的迁移成本几乎为零——API 完全兼容。唯一需要留意的是:

  1. Vue3 script setup 中用 defineProps 接收即可
  2. TypeScript 项目下类型推导比 Vue2 好得多,强烈建议配合 TS 使用
  3. 大型项目建议团队统一约定:所有带路由参数的页面组件都必须配合 props 配置

如果你已经用了 props: true,不妨逐步升级为函数模式——多花 3 行代码,换来组件完全解耦,值。


相关文章

精彩推荐