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

一、最基础的路由跳转,声明式与编程式导航的区别

terry 2天前 阅读数 19 #Vue

在 Vue2 开发单页面应用时,路由跳转是串联页面、实现交互逻辑的关键环节,不管是点击导航栏切换页面,还是根据用户操作动态跳转到指定路径,都得靠路由跳转来实现,但刚接触 Vue2 + vue-router 的同学,往往会疑惑「各种场景下怎么选跳转方式?传参、嵌套路由这些复杂情况咋处理?」今天就从基础到进阶,把 Vue2 路由跳转的门道拆明白。

Vue2 里实现路由跳转,核心有两种方式:声明式导航(用 <router-link> 组件)和 编程式导航(用 this.$router 里的方法),先搞清楚它们的区别,才能选对场景。

声明式导航:<router-link> 怎么用?

你可以把 <router-link> 理解成“能跳转的 <a> 标签”,但它不会像普通 <a> 那样刷新页面(毕竟是单页应用),基本用法是给 to 属性传目标路径,

<router-link to="/home">首页</router-link>
<router-link to="/about">关于我们</router-link>

如果要传更复杂的配置(比如命名路由、带参数),to 还能写成对象形式:

<!-- 假设路由配置里有 name: 'user' -->
<router-link :to="{ name: 'user', params: { id: 123 }}">用户123</router-link>

这种方式适合静态导航场景,比如页面顶部的导航栏、侧边菜单,用户点一下就跳转,逻辑简单直接。

编程式导航:this.$router.push 啥时候用?

编程式导航更灵活,适合需要逻辑判断后再跳转的场景(比如登录成功后跳转到首页、表单提交后跳转到结果页),核心方法是 this.$router.push(),它的作用是“往路由历史记录里添加一条新记录”,用法和 <router-link>to 类似,能传字符串路径或对象:

// 传字符串路径
this.$router.push('/home')
// 传对象(命名路由 + 参数)
this.$router.push({ 
  name: 'user', 
  params: { id: 123 } 
})

除了 push,还有 replacego 两个常用方法,后面会详细讲它们的区别~

带参数跳转:query 和 params 该怎么选?

做项目时,经常需要“跳转到详情页并传 ID”“搜索页带关键词跳转”这类需求,这时候得用路由传参,而传参又分 queryparams 两种方式,它们的区别和场景很关键。

query 传参:把参数“挂在 URL 上”

query 传参的逻辑类似 HTTP 的 GET 请求,参数会直接拼在 URL 后面(/user?id=123),用法是在跳转时给 query 字段传对象:

// 声明式(<router-link>)
<router-link :to="{ path: '/user', query: { id: 123 }}">用户123</router-link>
// 编程式(this.$router.push)
this.$router.push({ 
  path: '/user', 
  query: { id: 123 } 
})

特点:参数暴露在 URL 里,刷新页面后参数不会丢失;适合需要“分享链接带参数”“刷新后参数保留”的场景(比如搜索结果页,用户刷新后还能看到关键词)。

params 传参:把参数“藏在路由里”

params 传参需要配合命名路由动态路由匹配(路由配置里写 /user/:id),先看路由配置:

const router = new VueRouter({
  routes: [
    {
      name: 'user', // 命名路由
      path: '/user/:id', // 动态段 :id
      component: User
    }
  ]
})

然后跳转时,给 params 传对象:

// 声明式
<router-link :to="{ name: 'user', params: { id: 123 }}">用户123</router-link>
// 编程式
this.$router.push({ 
  name: 'user', 
  params: { id: 123 } 
})

这时候 URL 会变成 /user/123,参数“藏”在路径里,看起来更简洁,但要注意:如果用 path 而不是 name 跳转,params 会被忽略(因为 path 是硬编码的路径,无法和动态段匹配)。

特点:参数不在 URL 上明文显示(但其实动态段还是能看到),适合“参数不需要暴露、但希望 URL 更简洁”的场景;但刷新页面后参数会丢失(因为 params 本质是“路由组件的 props”,不是 URL 的一部分),如果想刷新不丢参数,要么改用 query,要么把参数写进路由的 path 里(像上面的 /user/:id 这样)。

编程式导航的更多技巧:push、replace、go 怎么玩?

前面讲了 push,但 replacego 也有各自的妙用,掌握它们能解决很多“跳转后回退”的问题。

push:添加新的历史记录

this.$router.push() 会往路由历史栈里新增一条记录,所以用户点浏览器的“返回”按钮,能回到上一个页面,比如从首页跳转到详情页,用 push 的话,返回能回到首页,这是最常用的跳转方式。

replace:替换当前历史记录

this.$router.replace()替换当前的历史记录,而不是新增,比如用户完成支付后跳转到“支付成功页”,这时候用 replace,用户点返回就不会回到“支付页”(避免重复支付),用法和 push 一样,只是把方法名换成 replace

this.$router.replace('/pay-success')

go:控制前进/后退步数

this.$router.go(n) 类似浏览器的 history.go(n)n 是数字,表示“前进/后退多少步”。

  • this.$router.go(-1):返回上一页(等同于浏览器的“返回”按钮)
  • this.$router.go(1):前进到下一页(如果历史记录里有)

实际开发中,“返回按钮”功能常用 go(-1) 实现,比如在页面右上角加个返回按钮:

<button @click="$router.go(-1)">返回</button>

嵌套路由场景下的跳转逻辑

很多项目会用“嵌套路由”(比如布局页里嵌套首页、个人中心),这时候跳转要注意路径的层级关系,先看一个嵌套路由的配置示例:

const router = new VueRouter({
  routes: [
    {
      path: '/layout',
      component: Layout, // 父组件
      children: [
        { path: 'home', component: Home }, // 子路由:/layout/home
        { path: 'profile', component: Profile } // 子路由:/layout/profile
      ]
    }
  ]
})

绝对路径 vs 相对路径

跳转嵌套路由时,路径可以用绝对路径(以 开头,/layout/home),也可以用相对路径(不以 开头,home)。

  • 绝对路径:适合在任意组件里跳转,路径写死,<router-link to="/layout/home">首页</router-link>
  • 相对路径:适合在父路由组件(Layout)里跳转,路径基于当前路由的路径,比如在 Layout 组件里,写 <router-link to="home">首页</router-link>,它会自动拼成 /layout/home,这样修改父路由的 path 时,子路由跳转不用跟着改,更灵活。

编程式跳转的小技巧

在父组件(Layout)里用编程式导航时,相对路径同样生效:

// Layout 组件里的方法
goToHome() {
  this.$router.push('home') // 等同于 push('/layout/home')
}

如果是在子组件(Home)里跳转到另一个子组件(Profile),用相对路径的话要注意层级,this.$router.push('../profile')(但这种情况少用,一般直接用绝对路径更清晰)。

路由守卫里的跳转:控制权限与流程

路由守卫是“跳转前/后拦截逻辑”,最常用的是全局前置守卫(beforeEach),可以用来做权限控制(比如未登录用户不能进个人中心)。

全局前置守卫:beforeEach

在路由配置文件里,给 routerbeforeEach 钩子:

router.beforeEach((to, from, next) => {
  // to:要跳转到的目标路由
  // from:当前离开的路由
  // next:必须调用的函数,决定是否跳转
  if (to.meta.requiresAuth && !isLogin()) { 
    // 如果目标路由需要授权,且用户未登录,跳转到登录页
    next({ name: 'login' }) 
  } else {
    // 否则放行
    next() 
  }
})

这里要注意:next 只能调用一次,否则会报错,如果在守卫里跳转(比如跳转到登录页),要避免“无限循环”——比如登录页也需要 requiresAuth,那逻辑要改成:

router.beforeEach((to, from, next) => {
  if (to.meta.requiresAuth && !isLogin()) { 
    if (to.name === 'login') {
      // 如果已经在登录页,说明用户没权限,留在登录页
      next(false) 
    } else {
      next({ name: 'login' })
    }
  } else {
    next()
  }
})

组件内守卫:beforeRouteEnter

组件内的守卫(beforeRouteEnter)能在“组件进入前”做逻辑,但要注意,beforeRouteEnter 执行时,组件实例(this)还没创建,所以如果要在跳转前操作组件数据,得用 next(vm => { ... })

export default {
  beforeRouteEnter(to, from, next) {
    // 这里 this 是 undefined
    next(vm => {
      // vm 是组件实例,可以操作 vm.data
      vm.fetchData() // 进入组件后调用获取数据的方法
    })
  }
}

常见跳转问题的排查与解决

实际开发中,路由跳转容易碰到“页面不更新”“参数丢失”“跳转失败”这些坑,这里总结几个高频问题的解法。

跳转后页面不更新:组件复用导致

比如从 /user/1 跳转到 /user/2,路由参数变了,但组件实例没销毁(Vue 为了性能复用组件),所以组件的 createdmounted 不会重新执行,页面也就不更新。

解法 1:监听 $route 的变化,在 watch 里处理逻辑:

export default {
  watch: {
    '$route'(to, from) {
      // 路由变化时,重新获取数据
      this.fetchData(to.params.id)
    }
  }
}

解法 2:给 <router-view>key,强制组件销毁重建:

<router-view :key="$route.fullPath"></router-view>

params 传参后刷新页面,参数丢失

前面讲过,params 传参如果没把参数写进路由的 path/user/:id),刷新时参数会丢失(因为 params 不是 URL 的一部分)。

解法:要么改用 query 传参(参数挂在 URL 上,刷新不丢),要么把参数配置成动态路由(/user/:id),这样参数会被包含在 URL 里,刷新也能保留。

编程式跳转没反应:检查路由配置和 this 指向

this.$router.push() 没效果,先检查这两点:

  • 路由配置是否正确:目标路由的 namepath 有没有拼写错误?有没有在 routes 里配置?
  • this 是否指向 Vue 实例:如果用箭头函数定义方法,this 会丢失,要改成普通函数:
// 错误:箭头函数导致 this 不是 Vue 实例
methods: {
  goToPage: () => {
    this.$router.push('/home') // this 是 undefined
  }
}
// 正确:普通函数
methods: {
  goToPage() {
    this.$router.push('/home')
  }
}

按场景选对方法,跳转更丝滑

Vue2 路由跳转的核心是选对声明式/编程式,分清 query/params,处理好嵌套和守卫,最后再梳理下不同场景的选择逻辑:

  • 静态导航(菜单、Tab)→ 用 <router-link> 声明式;
  • 逻辑判断后跳转(登录、表单提交)→ 用 this.$router.push/replace 编程式;
  • 带参数且需分享/刷新保留 → 用 query
  • 带参数且想 URL 简洁 → 用 params + 动态路由;
  • 嵌套路由跳转 → 优先用相对路径,减少硬编码;
  • 权限控制 → 用全局守卫 beforeEach 拦截;

把这些逻辑理顺,再遇到路由跳转的需求,就能快速选对方法,少踩坑啦~

版权声明

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

发表评论:

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

热门