{T}

router.push

基本用法

router.push() 会向 history 栈添加新记录,点击后退按钮可以返回之前的 URL。

javascript
// 字符串路径
router.push('/home')

// 对象路径
router.push({ path: '/home' })

// 命名路由
router.push({ name: 'Home' })

// 带查询参数
router.push({ path: '/user', query: { id: '123' } })

参数类型

javascript
// 1. 字符串
router.push('/user/123')

// 2. 对象
router.push({ path: '/user/123' })

// 3. 命名路由
router.push({ name: 'User', params: { id: '123' } })

// 4. 带查询参数
router.push({ path: '/user', query: { id: '123' } })
// URL: /user?id=123

// 5. 带 hash
router.push({ path: '/user', hash: '#section' })
// URL: /user#section

完整签名

javascript
router.push(location, onComplete?, onAbort?)

参数说明:

参数类型说明
locationstring | object路由位置信息
onCompleteFunction导航成功完成的回调
onAbortFunction导航中止的回调

使用示例

在组件内

javascript
export default {
  methods: {
    goToHome() {
      this.$router.push('/home')
    },
    
    goToUser() {
      this.$router.push({
        name: 'User',
        params: { id: 123 }
      })
    },
    
    goToSearch() {
      this.$router.push({
        path: '/search',
        query: {
          q: 'vue router',
          page: 1
        }
      })
    }
  }
}

带回调

javascript
this.$router.push(
  '/home',
  () => {
    console.log('导航成功')
  },
  () => {
    console.log('导航中止')
  }
)

Promise 用法

Vue Router 3.1+ 支持 Promise:

javascript
// 返回 Promise
this.$router.push('/home')
  .then(() => {
    console.log('导航成功')
  })
  .catch(err => {
    console.log('导航失败:', err)
  })

// 使用 async/await
async function navigate() {
  try {
    await this.$router.push('/home')
    console.log('导航成功')
  } catch (err) {
    console.log('导航失败:', err)
  }
}

params 与 query 的区别

javascript
// params - 作为 URL 的一部分
router.push({ name: 'User', params: { id: '123' } })
// URL: /user/123 (需要在路由中定义 /user/:id)

// query - 作为查询参数
router.push({ path: '/user', query: { id: '123' } })
// URL: /user?id=123
注意

如果提供了 pathparams 会被忽略:

javascript
// ❌ params 会被忽略
router.push({ path: '/user', params: { id: '123' } })
// URL: /user

// ✅ 使用 query 或命名路由
router.push({ path: '/user', query: { id: '123' } })
router.push({ name: 'User', params: { id: '123' } })

router.replace

基本用法

router.replace()router.push() 类似,但不会向 history 栈添加新记录,而是替换当前记录。

javascript
// 字符串
router.replace('/home')

// 对象
router.replace({ path: '/home' })

// 命名路由
router.replace({ name: 'Home' })

与 push 的区别

javascript
// 使用 push - 可以后退
router.push('/page1')
router.push('/page2')
// 历史记录: [page1, page2]
// 后退按钮可以回到 page1

// 使用 replace - 不能后退
router.push('/page1')
router.replace('/page2')
// 历史记录: [page2]
// 后退按钮不能回到 page1

应用场景

  • 登录后跳转(不保留登录页)
  • 表单提交成功后(不保留表单页)
  • 重置密码后(不保留重置页)
javascript
// 登录成功
async login() {
  const success = await this.$api.login(this.form)
  if (success) {
    // 替换当前记录,后退时不会回到登录页
    this.$router.replace('/dashboard')
  }
}

// 表单提交
async submitForm() {
  await this.$api.submitForm(this.form)
  // 替换当前记录,防止重复提交
  this.$router.replace('/success')
}

声明式写法

Vue SFC
<router-link to="/home" replace>首页</router-link>

router.go

基本用法

router.go(n) 在 history 记录中前进或后退 n 步。

javascript
// 前进 1 步(等同于 router.forward())
router.go(1)

// 后退 1 步(等同于 router.back())
router.go(-1)

// 前进 3 步
router.go(3)

// 后退 2 步
router.go(-2)

超出范围

如果 history 记录不够,router.go() 会静默失败:

javascript
// 假设 history 只有 2 条记录
router.go(-100) // 静默失败,什么都不会发生
router.go(100)  // 静默失败,什么都不会发生

简化方法

javascript
// 后退
router.back()
// 等同于
router.go(-1)

// 前进
router.forward()
// 等同于
router.go(1)

应用示例

Vue SFC
<template>
  <div>
    <button @click="goBack">返回</button>
    <button @click="goForward">前进</button>
    <button @click="goHome">返回首页</button>
  </div>
</template>

<script>
export default {
  methods: {
    goBack() {
      this.$router.back()
    },
    
    goForward() {
      this.$router.forward()
    },
    
    goHome() {
      this.$router.push('/')
    }
  }
}
</script>

导航位置对象

location 参数可以是字符串或对象,对象形式提供更多选项。

完整属性

javascript
{
  path: '/user',          // 路径
  name: 'User',           // 命名路由
  params: { id: '123' },  // 路由参数
  query: { page: 1 },     // 查询参数
  hash: '#section',       // hash 值
  
  // 完整 URL 示例: /user?page=1#section
}

属性说明

属性类型说明
pathstring路由路径
namestring路由名称
paramsobject路由参数(需配合命名路由或动态路由)
queryobjectURL 查询参数
hashstringURL hash 值

组合示例

javascript
// 命名路由 + params
router.push({
  name: 'UserDetail',
  params: { id: '123' }
})
// URL: /user/123

// path + query
router.push({
  path: '/search',
  query: { q: 'vue', page: 1 }
})
// URL: /search?q=vue&page=1

// name + params + query
router.push({
  name: 'Product',
  params: { category: 'phone' },
  query: { sort: 'price' }
})
// URL: /product/phone?sort=price

// path + hash
router.push({
  path: '/article',
  hash: '#comments'
})
// URL: /article#comments

导航控制

导航确认

使用 onCompleteonAbort 回调:

javascript
this.$router.push(
  '/user/123',
  () => {
    // 导航成功完成
    console.log('导航成功')
  },
  () => {
    // 导航中止(被导航守卫阻止或跳转到其他路由)
    console.log('导航中止')
  }
)

Promise 模式

javascript
// Vue Router 3.1+
try {
  await this.$router.push('/user/123')
  console.log('导航成功')
} catch (error) {
  if (error.name === 'NavigationDuplicated') {
    console.log('重复导航')
  } else {
    console.log('导航中止:', error)
  }
}

处理导航重复

Vue Router 3.1+ 会抛出 NavigationDuplicated 错误:

javascript
// 全局处理
import VueRouter from 'vue-router'

const originalPush = VueRouter.prototype.push
VueRouter.prototype.push = function push(location) {
  return originalPush.call(this, location).catch(err => {
    if (err.name !== 'NavigationDuplicated') {
      return Promise.reject(err)
    }
  })
}

// 或者在调用时捕获
this.$router.push('/home').catch(err => {})

实战示例

登录后跳转

Vue SFC
<template>
  <form @submit.prevent="handleLogin">
    <input v-model="form.username" placeholder="用户名" />
    <input v-model="form.password" type="password" placeholder="密码" />
    <button type="submit">登录</button>
  </form>
</template>

<script>
export default {
  data() {
    return {
      form: {
        username: '',
        password: ''
      }
    }
  },
  
  methods: {
    async handleLogin() {
      try {
        await this.$store.dispatch('user/login', this.form)
        
        // 登录成功,跳转到之前要访问的页面或首页
        const redirect = this.$route.query.redirect || '/'
        this.$router.replace(redirect)
        
        this.$message.success('登录成功')
      } catch (error) {
        this.$message.error('登录失败:' + error.message)
      }
    }
  }
}
</script>

表单提交后跳转

javascript
export default {
  methods: {
    async submitForm() {
      try {
        const id = await this.$api.createArticle(this.form)
        
        // 跳转到详情页
        this.$router.push({
          name: 'ArticleDetail',
          params: { id }
        })
        
        this.$message.success('创建成功')
      } catch (error) {
        this.$message.error('创建失败')
      }
    }
  }
}

带确认的导航

javascript
export default {
  methods: {
    leavePage() {
      if (this.hasUnsavedChanges) {
        this.$confirm('有未保存的更改,确定要离开吗?', '提示', {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          type: 'warning'
        }).then(() => {
          this.$router.push('/home')
        }).catch(() => {
          // 取消导航
        })
      } else {
        this.$router.push('/home')
      }
    }
  }
}

条件导航

javascript
export default {
  methods: {
    handleNavigate(role) {
      // 根据用户角色跳转到不同页面
      const routes = {
        admin: '/admin/dashboard',
        user: '/user/home',
        guest: '/login'
      }
      
      this.$router.push(routes[role] || '/')
    }
  }
}

定时跳转

Vue SFC
<template>
  <div class="countdown">
    <p>{{ countdown }} 秒后跳转到首页</p>
    <router-link to="/">立即跳转</router-link>
  </div>
</template>

<script>
export default {
  data() {
    return {
      countdown: 5,
      timer: null
    }
  },
  
  mounted() {
    this.timer = setInterval(() => {
      this.countdown--
      if (this.countdown <= 0) {
        clearInterval(this.timer)
        this.$router.replace('/')
      }
    }, 1000)
  },
  
  beforeDestroy() {
    clearInterval(this.timer)
  }
}
</script>

完整示例:导航工具函数

javascript
// utils/navigation.js

/**
 * 导航到指定路由
 */
export function navigateTo(router, location, replace = false) {
  const method = replace ? 'replace' : 'push'
  
  return router[method](location).catch(err => {
    if (err.name !== 'NavigationDuplicated') {
      throw err
    }
  })
}

/**
 * 返回上一页或指定页面
 */
export function goBack(router, fallback = '/') {
  if (window.history.length > 1) {
    router.back()
  } else {
    router.replace(fallback)
  }
}

/**
 * 刷新当前页面
 */
export function refreshPage(router) {
  const { path, query, params } = router.currentRoute
  router.replace({ path, query, params })
}

/**
 * 打开新标签页
 */
export function openInNewTab(router, location) {
  const route = router.resolve(location)
  window.open(route.href, '_blank')
}

使用示例:

javascript
import { navigateTo, goBack, refreshPage, openInNewTab } from '@/utils/navigation'

// 导航
await navigateTo(this.$router, '/user/123')

// 返回
goBack(this.$router, '/home')

// 刷新
refreshPage(this.$router)

// 新标签页打开
openInNewTab(this.$router, '/user/123')

最佳实践

1. 优先使用命名路由

javascript
// ✅ 推荐:使用命名路由
router.push({ name: 'UserDetail', params: { id: '123' } })

// ❌ 不推荐:硬编码路径
router.push('/user/123')

2. 登录后使用 replace

javascript
// ✅ 推荐
this.$router.replace('/dashboard')

// ❌ 不推荐
this.$router.push('/dashboard') // 后退会回到登录页

3. 捕获导航错误

javascript
// Vue Router 3.1+
this.$router.push('/home').catch(err => {
  if (err.name !== 'NavigationDuplicated') {
    console.error('导航错误:', err)
  }
})

4. 使用查询参数传递复杂数据

javascript
// 传递对象
router.push({
  path: '/search',
  query: {
    filters: JSON.stringify({ category: 'phone', price: [100, 500] })
  }
})

// 在目标组件解析
const filters = JSON.parse(this.$route.query.filters || '{}')

5. 避免在导航守卫中使用 push

javascript
// ❌ 不推荐:可能导致无限循环
router.beforeEach((to, from, next) => {
  if (!isAuthenticated()) {
    router.push('/login')  // 可能导致循环
    return
  }
  next()
})

// ✅ 推荐:使用 next
router.beforeEach((to, from, next) => {
  if (!isAuthenticated()) {
    next('/login')
    return
  }
  next()
})

常见问题

1. params 丢失?

确保使用命名路由或动态路由:

javascript
// ❌ params 会被忽略
router.push({ path: '/user', params: { id: '123' } })

// ✅ 使用命名路由
router.push({ name: 'User', params: { id: '123' } })

// ✅ 使用动态路由
// 路由配置: { path: '/user/:id', name: 'User', ... }
router.push({ name: 'User', params: { id: '123' } })

2. 如何传递大量数据?

使用 Vuex 或状态管理,而不是通过 URL:

javascript
// 存储数据
this.$store.commit('setTempData', largeData)

// 导航
this.$router.push('/preview')

// 在目标组件读取
const data = this.$store.state.tempData

3. 如何在新窗口打开?

javascript
const route = this.$router.resolve('/user/123')
window.open(route.href, '_blank')

4. 如何获取跳转前的路由?

javascript
// 在路由守卫中
router.afterEach((to, from) => {
  console.log('从', from.path, '跳转到', to.path)
})

// 在组件中
this.$router.beforeEach((to, from, next) => {
  console.log('来源路由:', from)
  next()
})