Vue Composition API中的路由守卫实践指南

1. 在setup中使用组件内守卫

在Vue 3的Composition API中,我们可以直接在setup()函数中使用组件内路由守卫,这为逻辑组织提供了更大的灵活性。

基本用法

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

export default {
  setup() {
    // 相当于 beforeRouteLeave
    onBeforeRouteLeave((to, from, next) => {
      const answer = window.confirm('确定要离开吗?未保存的更改将会丢失')
      if (answer) {
        next()
      } else {
        next(false)
      }
    })

    // 相当于 beforeRouteUpdate
    onBeforeRouteUpdate((to, from, next) => {
      // 对路由变化做出响应...
      next()
    })
  }
}

实践建议

  1. 守卫执行顺序:Composition API守卫与Options API守卫可以共存,执行顺序为:

    • beforeRouteUpdate (Options API)
    • onBeforeRouteUpdate (Composition API)
    • beforeRouteLeave (Options API)
    • onBeforeRouteLeave (Composition API)
  2. 异步处理:可以在守卫中直接使用async/await处理异步逻辑:
onBeforeRouteLeave(async (to, from, next) => {
  const canLeave = await checkUnsavedChanges()
  next(canLeave)
})
  1. 组合式使用:可以将守卫逻辑与其他Composition API功能结合:
import { ref } from 'vue'
import { onBeforeRouteLeave } from 'vue-router'

export default {
  setup() {
    const hasUnsavedChanges = ref(false)
    
    onBeforeRouteLeave((to, from, next) => {
      if (hasUnsavedChanges.value) {
        // 显示确认对话框
      } else {
        next()
      }
    })

    return { hasUnsavedChanges }
  }
}

2. 复用守卫逻辑的Composable函数设计

Composition API最大的优势之一是能够将逻辑提取为可复用的Composable函数,路由守卫逻辑也不例外。

基础守卫Composable示例

// useRouteGuard.js
import { onBeforeRouteLeave } from 'vue-router'

export function useUnsavedChangesGuard(hasChanges) {
  onBeforeRouteLeave((to, from, next) => {
    if (hasChanges.value) {
      const answer = window.confirm('您有未保存的更改,确定要离开吗?')
      answer ? next() : next(false)
    } else {
      next()
    }
  })
}

带参数的进阶Composable

// useAuthGuard.js
import { onBeforeRouteUpdate } from 'vue-router'

export function useAuthGuard(requiredRoles) {
  onBeforeRouteUpdate(async (to, from, next) => {
    const userRoles = await fetchUserRoles()
    const hasPermission = requiredRoles.some(role => 
      userRoles.includes(role)
    )
    
    hasPermission ? next() : next('/forbidden')
  })
}

组合多个守卫

// useCompositeGuards.js
import { useUnsavedChangesGuard } from './useRouteGuard'
import { useAuthGuard } from './useAuthGuard'

export function useCompositeGuards(options) {
  if (options.unsavedChanges) {
    useUnsavedChangesGuard(options.unsavedChanges)
  }
  
  if (options.requiredRoles) {
    useAuthGuard(options.requiredRoles)
  }
}

实践建议

  1. 命名约定:Composable函数应以use前缀开头,遵循Vue社区约定
  2. 类型安全:为Composable添加TypeScript类型定义:
// useRouteGuard.ts
import type { Ref } from 'vue'

export function useUnsavedChangesGuard(hasChanges: Ref<boolean>): void {
  // 实现...
}
  1. 测试策略:由于守卫与路由紧密耦合,建议:

    • 使用Jest或Vitest进行单元测试
    • 模拟vue-router的API
    • 验证next()调用的不同情况
  2. 性能考虑:避免在Composable中执行重逻辑,必要时使用防抖/节流:
import { debounce } from 'lodash-es'

export function useSearchGuard() {
  onBeforeRouteUpdate(debounce((to, from, next) => {
    // 处理搜索参数变化
    next()
  }, 300))
}

总结

Composition API为Vue路由守卫带来了新的可能性:

  1. 更灵活的代码组织:可以将守卫逻辑与相关功能放在一起
  2. 更好的复用性:通过Composable函数共享守卫逻辑
  3. 更强的类型支持:与TypeScript配合更自然
  4. 更清晰的测试边界:隔离测试守卫逻辑更容易

在实际项目中,建议根据团队习惯选择Options API或Composition API风格的守卫,或者两者结合使用,发挥各自的优势。

评论已关闭