Vue Routerの高度なナビゲーション制御と動的ルーティング

ナビゲーションガードの実装

グローバルガード

const router = createRouter({
  history: createWebHistory(),
  routes: [
    { path: '/', name: 'top', component: TopView },
    { path: '/profile', name: 'profile', component: ProfileView }
  ]
})

// グローバル前置ガード
router.beforeEach((destination, origin) => {
  if (destination.name === 'profile' && !isAuthenticated()) {
    return { name: 'login' }
  }
  return true
})

// グローバル解決ガード
router.beforeResolve(async destination => {
  if (destination.meta.requiresAuth) {
    await verifyUserSession()
  }
})

// グローバル後置フック
router.afterEach((destination, origin, navigationError) => {
  logNavigation(destination.path)
})

ルート固有ガード

const routeConfig = [
  {
    path: '/dashboard',
    component: Dashboard,
    beforeEnter: (destination, origin) => {
      return hasPermission(destination.query.accessLevel)
    }
  },
  {
    path: '/admin',
    component: AdminPanel,
    beforeEnter: [checkAdminRole, validateSession]
  }
]

コンポーネント内ガード

<script>
export default {
  beforeRouteEnter(destination, origin, proceed) {
    proceed(vm => vm.initData())
  },
  beforeRouteUpdate(destination, origin) {
    this.refreshContent(destination.params.id)
  },
  beforeRouteLeave(destination, origin) {
    return this.hasUnsavedChanges ? confirm('変更を破棄しますか?') : true
  }
}
</script>

ナビゲーション処理フロー

  1. ナビゲーション開始
  2. コンポーネントのbeforeRouteLeave呼出
  3. グローバルbeforeEach呼出
  4. 再利用コンポーネントのbeforeRouteUpdate呼出
  5. ルート設定内beforeEnter呼出
  6. 非同期コンポーネント解決
  7. アクティベート前beforeRouteEnter呼出
  8. グローバルbeforeResolve呼出
  9. ナビゲーション確定
  10. グローバルafterEach呼出
  11. DOM更新
  12. beforeRouteEnterのnextコールバック実行

ルートメタ情報と遅延読み込み

const routes = [
  {
    path: '/settings',
    component: () => import('./views/SettingsPage.vue'),
    meta: { requiresAuth: true, accessLevel: 2 }
  }
]

router.beforeEach((destination) => {
  if (destination.meta.requiresAuth) {
    return validateAuth()
  }
})

ナビゲーションエラーハンドリング

import { isNavigationFailure, NavigationFailureType } from 'vue-router'

async function navigateToUser() {
  const result = await router.push('/user/123')
  
  if (isNavigationFailure(result, NavigationFailureType.aborted)) {
    showToast('アクセスが拒否されました')
  }
}

router.afterEach((_, __, navigationError) => {
  if (navigationError) {
    logError(navigationError)
  }
})

動的ルーティング操作

// ルート追加
router.addRoute({ 
  path: '/reports', 
  component: () => import('./views/Reports.vue') 
})

// ルート削除
const removeReportRoute = router.addRoute(reportRoute)
removeReportRoute()

// 別名での削除
router.removeRoute('reports')

// ネストされたルート追加
router.addRoute('admin', {
  path: 'dashboard',
  component: AdminDashboard
})

// ルート存在確認
if (!router.hasRoute('backup')) {
  router.addRoute(backupRoute)
}

タグ: VueRouter Vue3 ナビゲーションガード ルーティング 動的ルーティング

6月18日 22:16 投稿