Vue2 与 Vue3 路由钩子的区别及用法详解

发布于:2025-09-01 ⋅ 阅读:(27) ⋅ 点赞:(0)

Vue2 与 Vue3 路由钩子的区别及用法详解

一、核心区别概览

特性 Vue2 (选项式API) Vue3 (组合式API)
定义方式 组件选项形式 在setup()中调用函数形式
钩子名称 beforeRouteEnter/Update/Leave onBeforeRouteUpdate/Leave
this访问 beforeRouteEnter不能访问this 无this概念,直接使用变量
异步处理 next回调处理 支持async/await
组合使用 难以复用 可轻松组合复用

二、Vue2 路由钩子详解

1. 三种组件内守卫

export default {
  // 1.进入路由前调用(不能访问this)
  beforeRouteEnter(to, from, next) {
    next(vm => {
      // 通过vm访问组件实例
    })
  },
  
  // 2.路由变化但组件复用时调用
  beforeRouteUpdate(to, from, next) {
    // 可以访问this
    if (to.params.id !== this.$route.params.id) {
      this.fetchData()
    }
    next()
  },
  
  // 3.离开路由前调用
  beforeRouteLeave(to, from, next) {
    if (this.unsavedChanges) {
      if (confirm('有未保存的更改!')) {
        next()
      } else {
        next(false)
      }
    } else {
      next()
    }
  }
}

2. 特点

  • beforeRouteEnter 是唯一不能访问this的守卫
  • 必须调用next()来解析钩子
  • 全局守卫(beforeEach等)仍可用

三、Vue3 路由钩子详解

1. 组合式API守卫

import { onBeforeRouteUpdate, onBeforeRouteLeave } from 'vue-router'

export default {
  setup() {
    const unsavedChanges = ref(false)
    
    // 1.路由更新守卫
    onBeforeRouteUpdate(async (to, from) => {
      // 不需要next参数(除非需要重定向)
      if (to.params.id !== from.params.id) {
        await fetchData(to.params.id)
      }
    })
    
    // 2.路由离开守卫
    onBeforeRouteLeave((to, from) => {
      if (unsavedChanges.value) {
        return confirm('确定要离开吗?')
      }
    })
    
    return { unsavedChanges }
  }
}

2. 重大变化

  1. 更简单的API

    • 移除了next函数(除非需要重定向)
    • 返回false取消导航,返回trueundefined继续导航
    • 可以返回路由路径字符串或对象进行重定向
  2. 更好的TypeScript支持

  3. 组合复用示例

// 可复用的路由守卫逻辑
function useRouteLeaveGuard(unsavedChanges) {
  onBeforeRouteLeave(() => {
    if (unsavedChanges.value) {
      return confirm('确定离开?')
    }
  })
}

// 组件中使用
setup() {
  const unsaved = ref(false)
  useRouteLeaveGuard(unsaved)
  // ...
}

四、迁移指南

从Vue2到Vue3的转换示例

Vue2版本

beforeRouteLeave(to, from, next) {
  if (this.unsavedChanges) {
    next(confirm('离开吗?'))
  } else {
    next()
  }
}

Vue3版本

setup() {
  const unsavedChanges = ref(false)
  
  onBeforeRouteLeave(() => {
    if (unsavedChanges.value) {
      return confirm('离开吗?')
    }
  })
}

注意事项

  1. beforeRouteEnter在Vue3中没有直接对应物,需要改用其他方式:

    // 替代方案:使用onMounted + 路由监听
    setup() {
      const userData = ref(null)
      
      onMounted(async () => {
        userData.value = await fetchUser(route.params.id)
      })
      
      watch(
        () => route.params.id,
        async (newId) => {
          userData.value = await fetchUser(newId)
        }
      )
    }
    
  2. 全局守卫(beforeEach等)在Vue3中用法保持不变

五、最佳实践建议

  1. Vue3推荐模式

    • 优先使用组合式函数封装可复用的路由逻辑
    • 利用async/await处理异步操作
    • 对于简单逻辑,直接返回布尔值而非使用next
  2. 复杂场景处理

// 需要重定向的复杂场景
onBeforeRouteLeave((to, from) => {
  if (needRedirect) {
    return { path: '/login', query: { from: to.fullPath } }
  }
  if (unsavedChanges.value) {
    return confirm('确定离开?')
  }
})
  1. 组合多个守卫
setup() {
  // 可以注册多个同类型守卫
  onBeforeRouteLeave(checkUnsavedChanges)
  onBeforeRouteLeave(logRouteChange)
  onBeforeRouteLeave(analyticsTracker)
}

网站公告

今日签到

点亮在社区的每一天
去签到