2、静态路由:声明式导航、编程式导航、路由参数传递(query/params)

好,咱们进入第二个实战环节。

静态路由,说白了就是路由表写死了的那种。你定义好路径,组件就固定在那里。虽然听起来简单,但这里面的门道可不少。我刚开始用 Vue Router 的时候,就老在导航方式和参数传递上栽跟头。

今天咱们就把这块彻底捋清楚。

2.1 声明式导航:<router-link> 的正确用法

声明式导航,就是你在模板里写 <router-link> 标签。它最终会被渲染成一个 <a> 标签。

我个人习惯,只要页面里有固定的导航菜单,一律用声明式。为什么?因为可读性好,而且 Vue Router 会自动处理高亮状态。

核心用法:

<!-- 基本用法 -->
<router-link to="/home">首页</router-link>

<!-- 带参数:query 方式 -->
<router-link :to="{ path: '/user', query: { id: 123, name: '张三' } }">
  用户详情
</router-link>

<!-- 带参数:params 方式(需要配合命名路由) -->
<router-link :to="{ name: 'UserDetail', params: { id: 456 } }">
  用户详情
</router-link>

这里有个坑,我必须要说。

我曾经踩过的坑:

params 的时候,千万不能用 path 来搭配。你写 :to="{ path: '/user', params: { id: 1 } }",params 会被直接忽略掉。嗯,Vue Router 就是这么设计的。必须用 name 来指定路由。

2.2 编程式导航:this.$router.pushreplace

编程式导航,就是在 JavaScript 代码里跳转。比如用户登录成功后,或者某个异步操作完成后,你需要手动跳转。

我一般用 this.$router.push 居多。它会在历史栈里加一条记录,用户点浏览器「后退」按钮能回去。

// 编程式导航示例
methods: {
  goToUser(id) {
    // query 方式
    this.$router.push({ path: '/user', query: { id: id } })

    // params 方式(命名路由)
    this.$router.push({ name: 'UserDetail', params: { id: id } })
  },

  // 替换当前记录,不留下历史
  replaceToHome() {
    this.$router.replace('/home')
  },

  // 前进/后退
  goBack() {
    this.$router.go(-1)
  }
}

我的小建议:

如果你在做表单提交,提交成功后用 replace 跳转。这样用户点后退,不会回到那个已经提交过的表单页面。用户体验会好很多。

2.3 路由参数传递:query vs params

这两个东西,很多新手搞混。其实区别很简单,我直接给你列个表。

对比项 query params
URL 形式 /user?id=123&name=张三 /user/123(需路由配置 /user/:id
刷新后是否丢失 不丢失 不丢失(但需配置路由参数)
获取方式 $route.query $route.params
适用场景 搜索条件、筛选参数 资源 ID、唯一标识

你想想看,为什么会有这两种方式?

说白了,query 适合那种「可选」的参数。比如搜索关键词,用户可能不传,URL 里就没有 ?keyword=xxx。而 params 适合「必选」的参数,比如用户 ID,没有 ID 你显示谁的信息?

实战中的参数获取:

// 在组件中获取参数
export default {
  created() {
    // 获取 query 参数
    const id = this.$route.query.id
    const name = this.$route.query.name

    // 获取 params 参数
    const userId = this.$route.params.id

    console.log('query:', id, name)
    console.log('params:', userId)
  }
}

2.4 路由配置与参数绑定

要让 params 生效,你得先在路由配置里定义好参数占位符。

// router/index.js
const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  },
  {
    path: '/user',
    name: 'User',
    component: User
  },
  {
    // 注意这里的 :id,就是 params 的占位符
    path: '/user/:id',
    name: 'UserDetail',
    component: UserDetail
  },
  {
    // 多个参数
    path: '/post/:year/:month/:day',
    name: 'PostDetail',
    component: PostDetail
  }
]

我在项目中遇到过一个问题:用户直接访问 /user/user/123,其实是两个不同的路由。如果你想让它们共用同一个组件,可以用 props 来解耦。

推荐做法:

$route 的耦合降到最低。用 props: true 把参数变成组件的 props。

// 路由配置
{
  path: '/user/:id',
  component: UserDetail,
  props: true  // 自动将 params 作为 props 传入
}

// 组件中直接接收
export default {
  props: ['id'],
  mounted() {
    console.log(this.id)  // 直接使用,不用再 $route.params.id
  }
}

这样组件更干净,也更容易测试。我个人强烈推荐这种方式。

2.5 常见问题与避坑指南

嗯,这里我总结几个我踩过的坑,你遇到了直接对照着看就行。

我曾经踩过的坑:

  • params 刷新丢失? 如果你用 $router.push({ name: 'User', params: { id: 1 } }),但路由配置里没有 /user/:id 这个路径,刷新后 params 就没了。记住:params 必须和路由路径中的占位符对应。
  • query 参数太长? 有些浏览器对 URL 长度有限制(比如 IE 的 2083 字符)。如果你传大量数据,别用 query,考虑用 params 或者 Vuex。
  • 同一个路由,参数变了但组件不刷新? 这是 Vue Router 的复用机制。解决方案:用 watch 监听 $route 变化,或者给 <router-view>:key="$route.fullPath"
// 监听路由变化的正确姿势
export default {
  watch: {
    '$route'(to, from) {
      // 路由变化时重新获取数据
      this.fetchData(to.params.id)
    }
  },
  methods: {
    fetchData(id) {
      // 你的数据请求逻辑
    }
  }
}

好了,静态路由这块就这些。说白了就是三件事:怎么跳、怎么传参、怎么拿参数。你把这三点搞明白,后面动态路由就好理解了。

下一节咱们聊动态路由匹配,那个才是真正体现 Vue Router 灵活性的地方。