一、最基础的路由跳转,声明式与编程式导航的区别
在 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,还有 replace 和 go 两个常用方法,后面会详细讲它们的区别~
带参数跳转:query 和 params 该怎么选?
做项目时,经常需要“跳转到详情页并传 ID”“搜索页带关键词跳转”这类需求,这时候得用路由传参,而传参又分 query 和 params 两种方式,它们的区别和场景很关键。
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,但 replace 和 go 也有各自的妙用,掌握它们能解决很多“跳转后回退”的问题。
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
在路由配置文件里,给 router 加 beforeEach 钩子:
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 为了性能复用组件),所以组件的 created、mounted 不会重新执行,页面也就不更新。
解法 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() 没效果,先检查这两点:
- 路由配置是否正确:目标路由的
name、path有没有拼写错误?有没有在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前端网发表,如需转载,请注明页面地址。
code前端网

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