基于VueJS Router Guards实现访问控制及路由加载范围限制
Got it, let's break down how to implement this access control exactly as you need it. The goal is to make sure main routes only load in App.vue's <router-view>, and nested routes only load in their parent component's <router-view>. Here's a step-by-step solution:
1. Mark Routes with Meta Information
First, add metadata to your routes to define where they're allowed to load. We'll use a allowedParent field in the meta object:
- For main routes (those meant for App.vue), set
allowedParent: null(since they have no parent route). - For nested routes, set
allowedParentto the name of their parent route (so we can verify they're loading under the correct parent).
import { createRouter, createWebHistory } from 'vue-router' import Home from '../views/Home.vue' import HomeProfile from '../views/HomeProfile.vue' import About from '../views/About.vue' import AboutTeam from '../views/AboutTeam.vue' const routes = [ // Main routes (only for App.vue's router-view) { path: '/home', name: 'Home', component: Home, meta: { allowedParent: null }, // Nested routes (only for Home.vue's router-view) children: [ { path: 'profile', name: 'HomeProfile', component: HomeProfile, meta: { allowedParent: 'Home' } } ] }, { path: '/about', name: 'About', component: About, meta: { allowedParent: null }, // Nested routes (only for About.vue's router-view) children: [ { path: 'team', name: 'AboutTeam', component: AboutTeam, meta: { allowedParent: 'About' } } ] } ] const router = createRouter({ history: createWebHistory(process.env.BASE_URL), routes })
2. Global Route Guard for Top-Level Checks
Add a global beforeEach guard to validate that every route is loading under its allowed parent. This catches cases where someone might try to navigate directly to a nested route without its parent, or misconfigure routes.
router.beforeEach((to, from, next) => { // Get the actual parent route (from the matched route hierarchy) const actualParentRoute = to.matched.length > 1 ? to.matched[to.matched.length - 2].name : null // Compare actual parent with allowed parent if (to.meta.allowedParent !== actualParentRoute) { const errorMsg = to.meta.allowedParent ? `Route "${to.name}" can only load under parent route "${to.meta.allowedParent}"` : `Route "${to.name}" can only load in App.vue's root router-view` console.error(errorMsg) // Redirect to a safe route (e.g., home) instead of allowing invalid navigation next({ name: 'Home' }) return } // All checks passed, proceed with navigation next() })
3. Component-Level Guards for Extra Safety
To prevent edge cases (like loading a nested route in a different parent component's <router-view> via programmatic navigation), add guards directly to components that contain a <router-view>.
For example, in Home.vue:
<template> <div class="home"> <h1>Home Page</h1> <router-view></router-view> </div> </template> <script> export default { name: 'Home', beforeRouteUpdate(to, from, next) { // Verify the incoming route is a child of Home and allowed here const isHomeChild = to.meta.allowedParent === 'Home' const isUnderHome = to.matched.some(route => route.name === 'Home') if (!isHomeChild || !isUnderHome) { console.error('This route can only load in Home.vue\'s router-view') next(false) // Block navigation return } next() } } </script>
Repeat this pattern in About.vue (or any other component with a <router-view>):
<template> <div class="about"> <h1>About Page</h1> <router-view></router-view> </div> </template> <script> export default { name: 'About', beforeRouteUpdate(to, from, next) { const isAboutChild = to.meta.allowedParent === 'About' const isUnderAbout = to.matched.some(route => route.name === 'About') if (!isAboutChild || !isUnderAbout) { console.error('This route can only load in About.vue\'s router-view') next(false) return } next() } } </script>
How This Works
- Global Guard: Checks the route hierarchy to ensure every route is nested under its allowed parent. This prevents invalid route configurations or direct URL manipulation.
- Component Guards: Adds an extra layer of safety to ensure that even if someone tries to load a route in the wrong component's
<router-view>(via$router.pushor other methods), the navigation is blocked.
This setup fully enforces your requirement: main routes stay in App.vue's router-view, and nested routes only load in their parent component's router-view.
内容的提问来源于stack exchange,提问作者margherita pizza

