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

Vue Router的router.push该怎么用?常见场景与细节解析

terry 3小时前 阅读数 8 #Vue
文章标签 push

在Vue项目里做页面跳转,router.push是绕不开的常用方法,但刚接触的同学常会疑惑——它具体怎么用?不同参数格式有啥区别?和router.replace咋选?遇到跳转没反应、参数丢了这些问题咋解决?今天就把router.push的用法、细节、场景和排坑技巧一次性讲清楚。

router.push基础用法是啥?

简单说,router.push是Vue Router提供的「编程式导航」方法,作用和模板里的声明式导航一样,都是用来跳转到目标路由,区别在于,是写在模板里的“声明式”跳转,适合页面结构里的静态跳转;而router.push是写在JS逻辑里的“编程式”跳转,适合需要判断条件、异步操作后再跳转的场景。

它的基本语法是this.$router.push(参数)(在组件里用,因为$router是Vue Router的实例;如果在Vuex、工具函数里,要确保能拿到router实例),这里的「参数」有两种常见格式:

  • 字符串格式:直接写目标路由的路径,比如跳转到关于页面:this.$router.push('/about')
  • 对象格式:通过路由的name(推荐,因为路径可能变但name不变)或者path,搭配参数(paramsquery),比如跳转到用户详情页,传用户ID:
    this.$router.push({  
      name: 'UserDetail', // 路由配置里的name  
      params: { id: 123 } // 动态路由参数,对应路由里的/:id  
    })  
    
    或者用path+query传参(适合非动态路由的场景):
    this.$router.push({  
      path: '/article',  
      query: { category: 'tech', page: 1 } // 会变成?category=tech&page=1  
    })  
    

这里得注意name和path的区别:用name时,路由的匹配基于「路由名称」,更稳定(比如后期路径改了,name不变就不影响跳转);用path时,是直接匹配路径字符串,适合简单场景。paramspath不能同时用(因为path是固定路径,params是动态参数,一起用的话params会被忽略),所以传动态参数必须用name + params

router.push传参有哪些门道?

传参是router.push的核心细节,分「动态路由参数(params)」和「查询参数(query)」两种,用法和场景差异很大,搞混了容易出问题。

动态路由参数(params):和路由配置绑定

动态路由参数要配合路由配置里的动态段,比如路由配置写这样:

const routes = [  
  {  
    path: '/user/:id', // 动态段:id  
    name: 'User',  
    component: User  
  }  
]  

这时用router.push({ name: 'User', params: { id: 123 } }),url会变成/user/123动态参数会被嵌入到url里,所以刷新页面时参数不会丢(因为url里存着呢),但如果路由配置里没有动态段,硬传params的话,参数会被忽略,跳转也可能失败。

用path传动态参数会失效!比如写this.$router.push({ path: '/user', params: { id: 123 } }),params会被默默丢掉,实际跳转到/user(如果路由里有这个配置),但参数没传过去,所以记住:动态参数必须用name + params

查询参数(query):带在url问号后面

查询参数是附加在url后面的键值对,格式是?key=value&key2=value2,它和路由配置是否有动态段无关,不管用name还是path都能传。

this.$router.push({  
  name: 'ArticleList',  
  query: { tag: 'vue', page: 2 }  
})  
// 或者用path  
this.$router.push({  
  path: '/article-list',  
  query: { tag: 'vue', page: 2 }  
})  

两种写法都会让url变成/article-list?tag=vue&page=2(假设name对应的path是/article-list),查询参数适合传非敏感、可暴露的信息,比如分页、筛选条件,刷新页面时,query参数也会保留(因为在url里),但如果是分享链接,别人打开也能拿到这些参数,这点要注意。

目标组件怎么拿参数?

不管是params还是query,目标组件里都要通过this.$route来获取(注意是$route,不是$router!$router是跳转方法,$route是当前路由的信息对象)。

// User组件里拿动态参数id  
const userId = this.$route.params.id  
// ArticleList组件里拿query参数  
const tag = this.$route.query.tag  
const page = this.$route.query.page  

如果是嵌套路由,子组件里的$route也是当前整个路由的信息,所以不用额外处理,直接拿就行。

router.push和router.replace有啥区别?

很多同学分不清这俩,其实核心差异是对浏览器历史记录的操作不同

  • router.push添加新的历史记录,比如从页面A跳转到B,再跳转到C,历史记录是[A, B, C],点返回会回到B,再点回到A。
  • router.replace替换当前历史记录,比如从A→B(用push),B→C(用replace),历史记录变成[A, C],点返回会直接从C回到A,跳过B。

场景选择上:

  • 需要保留「回退层级」的普通跳转,用push,比如用户从列表页点详情,看完详情回退到列表,这时候列表→详情用push,回退才能回到列表。
  • 不需要回退的场景,用replace,比如用户登录成功后跳转到首页,登录页不需要再被回退到(否则用户点返回又回到登录页,体验差),这时候用router.replace('/home');还有表单提交成功后跳转到结果页,也适合用replace,避免用户回退重复提交。

哪些场景必须用router.push?

不是所有跳转都要用router.push,但遇到这几种情况,只能用编程式导航(router.push或同类方法):

逻辑判断后跳转

比如用户访问需要权限的页面,先判断是否登录:

if (isLogin()) {  
  this.$router.push('/dashboard')  
} else {  
  this.$router.push('/login')  
}  

这种「先判断再决定跳哪」的逻辑,没法做(它是声明式,写死跳转目标),必须用router.push。

异步操作后跳转

比如提交表单、发请求获取数据后跳转:

async submitForm() {  
  const res = await this.$axios.post('/api/submit', this.form)  
  if (res.success) {  
    this.$router.push('/success-page') // 请求成功后跳结果页  
  }  
}  

异步操作是JS逻辑,只能用编程式导航触发跳转。

动态参数拼接

列表页点不同条目,传不同ID到详情页:

// 列表项循环里的点击事件  
handleClick(item) {  
  this.$router.push({  
    name: 'ProductDetail',  
    params: { id: item.id }  
  })  
}  

每个条目的ID是动态的,没法用写死,必须用router.push动态传参。

跨组件/跨逻辑层跳转

比如在Vuex的action里处理完数据后跳转:

// store/actions.js  
actions: {  
  async login({ commit }, userInfo) {  
    const res = await api.login(userInfo)  
    commit('SET_TOKEN', res.token)  
    router.push('/home') // 这里router要引入Vue Router实例  
  }  
}  

或者在全局的事件总线、自定义指令里触发跳转,这些场景没有模板,只能用编程式导航。

router.push常见问题咋解决?

用router.push时,最头疼的是「跳转没反应」「参数丢了」「重复跳转报错」这些问题,逐个拆解:

跳转没反应?先查路由配置

常见原因:

  • 路径/name不匹配:比如路由配置里path是/goods,但push写的是/product,自然跳不过去,要确保push的路径或name和路由配置一致。
  • 参数类型不匹配:动态路由参数要求是字符串/数字,如果你传了对象、数组,会导致路由匹配失败,比如路由是/user/:id,但params传了{ id: { userId: 123 } },就会出错。
  • 路由嵌套没配对:如果是子路由,要确保父路由的path和子路由的children配置正确,比如父路由path是/parent,子路由path写child,那么完整路径是/parent/child,push的时候要写对路径或name。

参数丢失?分清params和path的关系

最容易踩的坑是「用path传params导致参数丢失」。path和params不能一起用!如果要传params,必须用name。

// 错误写法:path + params,params会被忽略  
this.$router.push({  
  path: '/user',  
  params: { id: 123 }  
})  
// 正确写法:name + params  
this.$router.push({  
  name: 'User',  
  params: { id: 123 }  
})  

如果是query参数,不管用name还是path都能传,不会丢,还有种情况:动态路由的params刷新后还在吗?在的,因为它在url里(user/123),刷新时浏览器会保留url,所以参数还在,但如果是用path+params且没在url里(比如上面的错误写法),刷新后参数就没了,因为没写到url里。

重复跳转同一路由报错?分版本处理

Vue Router 3.x版本中,重复调用push跳转到当前路由(比如当前在/home,又push('/home')),会抛出错误(Uncaught (in promise) NavigationDuplicated),解决方法:

  • 判断当前路由再跳转:在push前检查当前路由是否和目标路由一致,不一致再跳。
    if (this.$route.name!== 'Home') {  
      this.$router.push('/home')  
    }  
    
  • 捕获Promise异常:因为router.push返回Promise,所以可以用catch吞掉错误:
    this.$router.push('/home').catch(err => {  
      // 这里err是NavigationDuplicated错误,可忽略  
    })  
    

Vue Router 4.x版本已经优化了这个问题,重复跳转同一路由不会报错,所以如果是新项目,升级到4.x能避免这个麻烦。

路由嵌套导致跳转异常?检查相对路径

在嵌套路由的子组件里跳转时,容易犯的错是「路径写绝对路径还是相对路径」,比如父路由是/parent,子路由是children: [{ path: 'child', name: 'Child' }],那么子组件里push('../')会回到父路由(/parent),push('grandchild')会跳转到/parent/child/grandchild(如果有对应的子路由),如果搞不清层级,建议用name跳转,更直观。

进阶技巧:router.push的Promise与导航守卫

router.push返回的是Promise,这在处理「跳转成功/失败」时很有用,比如导航被守卫拦截(比如权限不足),Promise会reject,我们可以在catch里处理。

Promise风格的跳转

Vue Router 3和4中,router.push都返回Promise:

this.$router.push('/forbidden')  
  .then(() => {  
    // 跳转成功(但如果被守卫拦截,不会走到这里)  
  })  
  .catch(err => {  
    // 跳转失败,比如被beforeEach守卫next(false)拦截  
    console.log('跳转被阻止', err)  
  })  

结合导航守卫,能更细粒度控制跳转逻辑,比如全局前置守卫:

router.beforeEach((to, from, next) => {  
  if (to.path === '/admin' && !isAdmin()) {  
    next(false) // 阻止跳转  
  } else {  
    next() // 允许跳转  
  }  
})  

当用户没有权限访问/admin时,push('/admin')的Promise会catch到错误。

组件内导航守卫配合

组件内的beforeRouteEnter、beforeRouteUpdate等守卫,也能和router.push联动,比如在beforeRouteEnter里判断参数是否合法,不合法就跳转到错误页:

export default {  
  beforeRouteEnter(to, from, next) {  
    if (!to.params.id) {  
      next({ name: 'ErrorPage' }) // 跳错误页  
    } else {  
      next()  
    }  
  }  
}  

这种场景下,router.push触发的导航会经过组件内的守卫,实现更灵活的权限和参数校验。

router.push是Vue Router编程式导航的核心,掌握它的参数格式、传参细节、和replace的区别、常见问题解决,才能在项目里流畅处理页面跳转,记住核心逻辑:按场景选push或replace,传参分清params(动态路由)和query(查询参数),遇到问题先查路由配置和参数格式,结合导航守卫做更细的控制,把这些知识点吃透,不管是普通业务页跳转,还是复杂权限控制、异步跳转,都能游刃有余~

版权声明

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

发表评论:

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

热门