前端核心框架vue之(路由核心案例篇3/5)

写在前面的话:这是一个综合的案例,涉及到守卫,重定向。入门初级的兄弟们可以逐个技术栈速通,不要沉迷知识点的学习过程,实操可能更加的重要主包写了两三天

建议用时(2天-5天)

📘 Vue CLI 路由专项训练_前端开发文档

🧭 项目目标

开发一个具有完整前端路由功能的单页应用,涵盖权限控制、路由跳转、动态嵌套路由、查询参数、懒加载、重定向与 404 页面处理,用于 Vue Router 的专项训练。

📦 技术要求

  • Vue 2.x
  • Vue Router 3.x
  • Vue CLI 构建
  • Element UI 用于页面 UI
  • 项目目录结构清晰、组件模块划分合理

📁 项目结构建议

复制代码
src/
├── main.js
├── router/
│   ├── index.js          // 路由配置
│   └── guards.js         // 路由守卫
├── views/
│   ├── Home.vue
│   ├── About.vue
│   ├── Products.vue
│   ├── Dashboard.vue
│   ├── Admin.vue
│   ├── RedirectInfo.vue
│   ├── NotFound.vue
│   └── user/
│       ├── UserDetail.vue
│       ├── UserProfile.vue
│       └── UserSettings.vue
└── App.vue

📍 路由功能要求

✅ 基础页面

  • / 首页
  • /about 关于页面
  • 页面中按钮跳转需通过路由控制

🔐 路由权限控制

  • /dashboard:登录后才能访问
  • /admin:仅管理员才能访问
  • 配置路由元信息 meta.requiresAuth / meta.requiresAdmin

🔗 动态 & 嵌套路由

  • /user/:id:用户详情页
  • 嵌套:/user/:id/profile/user/:id/settings
  • 子页面通过 <router-view> 展示

🔍 查询参数

  • /products?category=xxx&page=1
  • 页面应能读取并展示查询条件

📦 懒加载路由

  • /lazy:以异步组件形式加载页面
  • 页面应模拟加载延迟(2秒左右)

🔁 重定向

  • /redirect-test/about
  • /old-dashboard/dashboard

🚫 404 页面

  • 无匹配路径 → 显示 NotFound 页面

总览:

模块 要求说明
基础路由配置 所有页面路径与组件绑定正确
页面跳转 页面内跳转通过 $router 实现
动态路由 能读取用户 ID 并展示相关内容
嵌套路由 子页面通过嵌套路由显示
查询参数处理 页面可读写查询参数,刷新保持状态
路由守卫 登录/权限控制逻辑合理,跳转提示完整
懒加载实现 页面实现异步加载逻辑并显示加载提示
重定向与 404 能正常重定向,404 页面显示无误
路由导航栏高亮状态 导航菜单可识别当前路由状态

这里是参考答案,直接运行单个HTML文件即可

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Vue Router 核心功能训练 - 修复版</title>
  
  <!-- Element Plus CSS -->
  <link rel="stylesheet" href="https://unpkg.com/element-plus@2.4.4/dist/index.css">
  
  <!-- Vue 3 -->
  <script src="https://unpkg.com/vue@3.3.8/dist/vue.global.js"></script>
  
  <!-- Vue Router 4 -->
  <script src="https://unpkg.com/vue-router@4.2.5/dist/vue-router.global.js"></script>
  
  <!-- Element Plus -->
  <script src="https://unpkg.com/element-plus@2.4.4/dist/index.full.js"></script>
  
  <!-- Element Plus Icons -->
  <script src="https://unpkg.com/@element-plus/icons-vue@2.1.0/dist/index.iife.min.js"></script>
</head>
<body>
  <div id="app"></div>

  <script>
    const { createApp, ref, reactive, computed } = Vue;
    const { createRouter, createWebHashHistory } = VueRouter;
    const { ElMessage, ElMessageBox } = ElementPlus;

    // 权限状态管理 - 修复响应式问题
    const authState = reactive({
      isLoggedIn: false,  // 直接使用普通值,不需要ref
      isAdmin: false,     // 直接使用普通值,不需要ref  
      username: '',       // 直接使用普通值,不需要ref
      
      async login() {
        try {
          // 模拟登录过程
          const { value: credentials } = await ElMessageBox.prompt('请输入用户名 (admin/user)', '登录', {
            confirmButtonText: '登录',
            cancelButtonText: '取消',
            inputPattern: /\S+/,
            inputErrorMessage: '用户名不能为空'
          });
          
          // 预设账号逻辑
          if (credentials === 'admin') {
            this.isLoggedIn = true;
            this.isAdmin = true;
            this.username = 'admin';
            ElMessage.success('🎉 管理员登录成功!');
          } else if (credentials === 'user') {
            this.isLoggedIn = true;
            this.isAdmin = false;
            this.username = 'user';
            ElMessage.success('✅ 普通用户登录成功!');
          } else {
            // 其他用户名默认为普通用户
            this.isLoggedIn = true;
            this.isAdmin = false;
            this.username = credentials;
            ElMessage.success(`✅ 用户 ${credentials} 登录成功!`);
          }
          
          console.log('登录状态已更新 - 登录:', this.isLoggedIn, '管理员:', this.isAdmin, '用户名:', this.username);
        } catch {
          ElMessage.info('取消登录');
        }
      },
      
      logout() {
        console.log('开始退出登录...');
        this.isLoggedIn = false;
        this.isAdmin = false;
        this.username = '';
        ElMessage.success('退出登录成功');
        console.log('退出登录完成 - 登录:', this.isLoggedIn, '管理员:', this.isAdmin, '用户名:', this.username);
      },
      
      setAdmin() {
        console.log('尝试设为管理员 - 当前登录状态:', this.isLoggedIn, '用户名:', this.username);
        if (!this.isLoggedIn) {
          ElMessage.warning('请先登录');
          return;
        }
        this.isAdmin = true;
        ElMessage.success(`${this.username} 已设置为管理员`);
        console.log('设为管理员完成 - 管理员状态:', this.isAdmin);
      },
      
      setUser() {
        console.log('尝试设为普通用户 - 当前登录状态:', this.isLoggedIn, '用户名:', this.username);
        if (!this.isLoggedIn) {
          ElMessage.warning('请先登录');
          return;
        }
        this.isAdmin = false;
        ElMessage.success(`${this.username} 已设置为普通用户`);
        console.log('设为普通用户完成 - 管理员状态:', this.isAdmin);
      },
      
      getStatusText() {
        if (!this.isLoggedIn) return '未登录';
        const role = this.isAdmin ? '管理员' : '普通用户';
        return `${this.username} (${role})`;
      }
    });

    // 用户设置数据(持久化)
    const userSettings = reactive({
      data: {},
      
      save(userId, settings) {
        this.data[userId] = { ...settings };
        ElMessage.success('设置保存成功');
      },
      
      load(userId) {
        return this.data[userId] || {
          emailNotify: true,
          smsNotify: false,
          privacy: 'public'
        };
      }
    });

    // 路由组件

    // 首页
    const Home = {
      template: `
        <div>
          <el-alert title="Vue Router 核心功能训练 - 修复版" type="success" show-icon />
          
          <!-- 权限控制面板 -->
          <el-card style="margin-top: 20px;">
            <template #header>
              <span>权限控制面板 - 路由守卫测试</span>
            </template>
            
            <!-- 添加账号说明 -->
            <el-alert 
              title="测试账号说明" 
              type="info" 
              :closable="false"
              style="margin-bottom: 15px;"
            >
              <p><strong>管理员账号:</strong> admin</p>
              <p><strong>普通用户:</strong> user</p>
              <p><strong>其他用户名:</strong> 默认为普通用户</p>
            </el-alert>
            
            <div style="margin-bottom: 15px;">
              当前状态: <el-tag :type="getTagType()">{{ authState.getStatusText() }}</el-tag>
            </div>
            <el-space>
              <el-button @click="handleLogin" type="success" :disabled="authState.isLoggedIn">
                <el-icon><User /></el-icon>
                登录
              </el-button>
              <el-button @click="handleLogout" type="info" :disabled="!authState.isLoggedIn">
                <el-icon><SwitchButton /></el-icon>
                退出登录
              </el-button>
              <el-button @click="handleSetAdmin" type="danger" :disabled="authState.isAdmin || !authState.isLoggedIn">
                <el-icon><Crown /></el-icon>
                设为管理员
              </el-button>
              <el-button @click="handleSetUser" type="warning" :disabled="!authState.isAdmin">
                <el-icon><Avatar /></el-icon>
                设为普通用户
              </el-button>
            </el-space>
          </el-card>
          
          <el-row :gutter="20" style="margin-top: 20px;">
            <el-col :span="12">
              <el-card header="基础路由">
                <el-button @click="$router.push('/about')" block>
                  <el-icon><InfoFilled /></el-icon>
                  关于页面
                </el-button>
              </el-card>
            </el-col>
            
            <el-col :span="12">
              <el-card header="动态路由">
                <el-button @click="$router.push('/user/123')" block>
                  <el-icon><User /></el-icon>
                  用户 123
                </el-button>
              </el-card>
            </el-col>
          </el-row>

          <el-row :gutter="20" style="margin-top: 20px;">
            <el-col :span="12">
              <el-card header="查询参数">
                <el-button @click="$router.push('/products?category=books')" block>
                  <el-icon><Reading /></el-icon>
                  图书分类
                </el-button>
              </el-card>
            </el-col>
            
            <el-col :span="12">
              <el-card header="路由守卫测试">
                <el-space direction="vertical" style="width: 100%;">
                  <el-button @click="$router.push('/dashboard')" type="primary" block>
                    <el-icon><DataBoard /></el-icon>
                    需要登录
                  </el-button>
                  <el-button @click="$router.push('/admin')" type="danger" block>
                    <el-icon><Setting /></el-icon>
                    需要管理员
                  </el-button>
                </el-space>
              </el-card>
            </el-col>
          </el-row>

          <el-row :gutter="20" style="margin-top: 20px;">
            <el-col :span="24">
              <el-card header="其他功能">
                <el-space>
                  <el-button @click="$router.push('/lazy')" type="warning">
                    <el-icon><Loading /></el-icon>
                    懒加载
                  </el-button>
                  <el-button @click="testRedirect" type="info">
                    <el-icon><Right /></el-icon>
                    重定向测试
                  </el-button>
                  <el-button @click="$router.push('/notfound')" type="danger">
                    <el-icon><WarningFilled /></el-icon>
                    404测试
                  </el-button>
                </el-space>
              </el-card>
            </el-col>
          </el-row>
        </div>
      `,
      computed: {
        authState() {
          return authState;
        }
      },
      methods: {
        async handleLogin() {
          console.log('点击登录按钮');
          await authState.login();
          this.$forceUpdate(); // 强制更新组件
        },
        handleLogout() {
          console.log('点击退出登录按钮');
          authState.logout();
          this.$forceUpdate(); // 强制更新组件
        },
        handleSetAdmin() {
          console.log('点击设为管理员按钮');
          authState.setAdmin();
          this.$forceUpdate(); // 强制更新组件
        },
        handleSetUser() {
          console.log('点击设为普通用户按钮');
          authState.setUser();
          this.$forceUpdate(); // 强制更新组件
        },
        getTagType() {
          if (!authState.isLoggedIn) return 'info';
          return authState.isAdmin ? 'danger' : 'success';
        },
        testRedirect() {
          ElMessage.info('即将重定向到关于页面...');
          setTimeout(() => {
            this.$router.push('/redirect-test');
          }, 1000);
        }
      }
    };

    // 关于页面
    const About = {
      template: `
        <div>
          <el-alert title="关于页面 - 基础路由演示" type="info" show-icon />
          <el-card style="margin-top: 20px;">
            <p>这是一个基础路由页面,演示了简单的页面跳转功能。</p>
            <el-divider />
            <p><strong>路由信息:</strong></p>
            <ul>
              <li>路径: {{ $route.path }}</li>
              <li>名称: {{ $route.name || '未命名' }}</li>
              <li>来源: {{ $route.meta.from || '直接访问' }}</li>
            </ul>
            <el-space style="margin-top: 20px;">
              <el-button @click="$router.back()" icon="ArrowLeft">返回上页</el-button>
              <el-button @click="$router.push('/')" type="primary" icon="House">返回首页</el-button>
            </el-space>
          </el-card>
        </div>
      `
    };

    // 重定向说明页面
    const RedirectInfo = {
      template: `
        <div>
          <el-alert title="重定向演示页面" type="warning" show-icon />
          <el-card style="margin-top: 20px;">
            <p>🎯 <strong>重定向逻辑说明:</strong></p>
            <ol>
              <li>当您访问 <code>/redirect-test</code> 时</li>
              <li>路由会自动重定向到 <code>/about</code> 页面</li>
              <li>但会在 about 页面的 meta 中标记来源为 "重定向"</li>
            </ol>
            
            <el-divider />
            
            <p><strong>测试重定向:</strong></p>
            <el-space direction="vertical" style="width: 100%;">
              <el-button @click="testRedirect1" type="primary" block>
                测试重定向 1: /redirect-test → /about
              </el-button>
              <el-button @click="testRedirect2" type="success" block>
                测试重定向 2: /old-dashboard → /dashboard (需要登录)
              </el-button>
              <el-button @click="testRedirect3" type="warning" block>
                测试重定向 3: /legacy-admin → /admin (需要管理员)
              </el-button>
            </el-space>
            
            <el-space style="margin-top: 20px;">
              <el-button @click="$router.back()" icon="ArrowLeft">返回上页</el-button>
              <el-button @click="$router.push('/')" type="primary" icon="House">返回首页</el-button>
            </el-space>
          </el-card>
        </div>
      `,
      methods: {
        testRedirect1() {
          ElMessage.info('即将重定向: /redirect-test → /about');
          setTimeout(() => {
            this.$router.push('/redirect-test');
          }, 1000);
        },
        testRedirect2() {
          ElMessage.info('即将重定向: /old-dashboard → /dashboard');
          setTimeout(() => {
            this.$router.push('/old-dashboard');
          }, 1000);
        },
        testRedirect3() {
          ElMessage.info('即将重定向: /legacy-admin → /admin');
          setTimeout(() => {
            this.$router.push('/legacy-admin');
          }, 1000);
        }
      }
    };

    // 用户详情页面 - 动态路由
    const UserDetail = {
      template: `
        <div>
          <el-alert :title="'用户详情 - ID: ' + $route.params.id + ' (动态路由)'" type="success" show-icon />
          
          <el-card style="margin-top: 20px;">
            <p><strong>用户ID:</strong> {{ $route.params.id }}</p>
            <p><strong>用户名:</strong> 用户{{ $route.params.id }}</p>
            
            <el-divider content-position="left">嵌套路由</el-divider>
            
            <el-space>
              <el-button @click="$router.push('/user/' + $route.params.id + '/profile')" type="primary">
                <el-icon><User /></el-icon>
                个人资料
              </el-button>
              <el-button @click="$router.push('/user/' + $route.params.id + '/settings')" type="success">
                <el-icon><Setting /></el-icon>
                账户设置
              </el-button>
            </el-space>
            
            <!-- 嵌套路由出口 -->
            <div style="margin-top: 20px;">
              <router-view></router-view>
            </div>
            
            <el-divider />
            
            <el-space>
              <el-button @click="$router.back()" icon="ArrowLeft">返回上页</el-button>
              <el-button @click="$router.push('/')" type="primary" icon="House">返回首页</el-button>
            </el-space>
          </el-card>
        </div>
      `
    };

    // 用户资料 - 嵌套路由
    const UserProfile = {
      template: `
        <el-card>
          <template #header>
            <el-icon><User /></el-icon>
            个人资料 (嵌套路由)
          </template>
          <p><strong>真实姓名:</strong> 用户{{ $route.params.id }}</p>
          <p><strong>邮箱:</strong> user{{ $route.params.id }}@example.com</p>
          <p><strong>注册时间:</strong> 2024-01-01</p>
          <p><strong>最后登录:</strong> {{ new Date().toLocaleString() }}</p>
        </el-card>
      `
    };

    // 用户设置 - 嵌套路由
    const UserSettings = {
      template: `
        <el-card>
          <template #header>
            <el-icon><Setting /></el-icon>
            账户设置 (嵌套路由)
          </template>
          <el-form label-width="100px">
            <el-form-item label="邮件通知">
              <el-switch v-model="settings.emailNotify" />
            </el-form-item>
            <el-form-item label="短信通知">
              <el-switch v-model="settings.smsNotify" />
            </el-form-item>
            <el-form-item label="隐私设置">
              <el-select v-model="settings.privacy">
                <el-option label="公开" value="public" />
                <el-option label="仅好友" value="friends" />
                <el-option label="私密" value="private" />
              </el-select>
            </el-form-item>
            <el-form-item>
              <el-button type="primary" @click="save">保存设置</el-button>
              <el-button @click="reset">重置</el-button>
            </el-form-item>
          </el-form>
          
          <el-divider />
          <p><strong>当前设置:</strong></p>
          <pre>{{ JSON.stringify(settings, null, 2) }}</pre>
        </el-card>
      `,
      data() {
        return {
          settings: {}
        };
      },
      created() {
        this.loadSettings();
      },
      watch: {
        '$route'() {
          this.loadSettings();
        }
      },
      methods: {
        loadSettings() {
          this.settings = userSettings.load(this.$route.params.id);
        },
        save() {
          userSettings.save(this.$route.params.id, this.settings);
        },
        reset() {
          this.settings = {
            emailNotify: true,
            smsNotify: false,
            privacy: 'public'
          };
          ElMessage.info('设置已重置');
        }
      }
    };

    // 商品页面 - 查询参数
    const Products = {
      template: `
        <div>
          <el-alert title="商品列表 - 查询参数演示" type="warning" show-icon />
          
          <el-card style="margin-top: 20px;">
            <el-alert :title="'当前URL: ' + $route.fullPath" type="info" :closable="false" />
            
            <el-form :inline="true" style="margin-top: 20px;">
              <el-form-item label="分类">
                <el-select v-model="category" @change="updateQuery">
                  <el-option label="全部" value="" />
                  <el-option label="图书" value="books" />
                  <el-option label="电子产品" value="electronics" />
                  <el-option label="服装" value="clothing" />
                </el-select>
              </el-form-item>
              <el-form-item label="页码">
                <el-input-number v-model="page" :min="1" @change="updateQuery" />
              </el-form-item>
              <el-form-item>
                <el-button @click="resetQuery">重置</el-button>
              </el-form-item>
            </el-form>
            
            <p style="margin-top: 20px;">
              <strong>筛选结果:</strong> 
              {{ category ? '分类: ' + category : '全部商品' }}
              {{ page > 1 ? ', 第' + page + '页' : '' }}
            </p>
            
            <el-space style="margin-top: 20px;">
              <el-button @click="$router.back()">返回上页</el-button>
              <el-button @click="$router.push('/')" type="primary">返回首页</el-button>
            </el-space>
          </el-card>
        </div>
      `,
      data() {
        return {
          category: '',
          page: 1
        };
      },
      created() {
        const query = this.$route.query;
        this.category = query.category || '';
        this.page = parseInt(query.page) || 1;
      },
      watch: {
        '$route'() {
          const query = this.$route.query;
          this.category = query.category || '';
          this.page = parseInt(query.page) || 1;
        }
      },
      methods: {
        updateQuery() {
          const query = {};
          if (this.category) query.category = this.category;
          if (this.page > 1) query.page = this.page;
          this.$router.push({ path: '/products', query: query });
        },
        resetQuery() {
          this.$router.push('/products');
        }
      }
    };

    // 数据面板 - 需要登录
    const Dashboard = {
      template: `
        <div>
          <el-alert title="数据面板 - 路由守卫演示 (需要登录)" type="success" show-icon />
          <el-card style="margin-top: 20px;">
            <p>🎉 恭喜!您已通过登录验证,可以访问此页面。</p>
            <p>当前用户状态: <el-tag type="success">{{ authState.getStatusText() }}</el-tag></p>
            <p>访问时间: {{ new Date().toLocaleString() }}</p>
            <el-space style="margin-top: 20px;">
              <el-button @click="$router.back()">返回上页</el-button>
              <el-button @click="$router.push('/')" type="primary">返回首页</el-button>
            </el-space>
          </el-card>
        </div>
      `,
      computed: {
        authState() {
          return authState;
        }
      }
    };

    // 管理员页面 - 需要管理员权限
    const Admin = {
      template: `
        <div>
          <el-alert title="管理员页面 - 路由守卫演示 (需要管理员权限)" type="danger" show-icon />
          <el-card style="margin-top: 20px;">
            <p>🎉 恭喜!您拥有管理员权限,可以访问此页面。</p>
            <p>当前用户状态: <el-tag type="danger">{{ authState.getStatusText() }}</el-tag></p>
            <p>访问时间: {{ new Date().toLocaleString() }}</p>
            <el-space style="margin-top: 20px;">
              <el-button @click="$router.back()">返回上页</el-button>
              <el-button @click="$router.push('/')" type="primary">返回首页</el-button>
            </el-space>
          </el-card>
        </div>
      `,
      computed: {
        authState() {
          return authState;
        }
      }
    };

    // 懒加载页面
    const LazyPage = {
      template: `
        <div>
          <el-alert title="懒加载页面 - 异步组件演示" type="warning" show-icon />
          <el-card style="margin-top: 20px;">
            <p>🎉 这个页面通过懒加载方式加载,模拟了2秒加载时间。</p>
            <p>加载完成时间: {{ new Date().toLocaleString() }}</p>
            <el-space style="margin-top: 20px;">
              <el-button @click="$router.back()">返回上页</el-button>
              <el-button @click="$router.push('/')" type="primary">返回首页</el-button>
            </el-space>
          </el-card>
        </div>
      `
    };

    // 404页面
    const NotFound = {
      template: `
        <el-result
          icon="warning"
          title="404"
          sub-title="页面未找到"
        >
          <template #extra>
            <el-space>
              <el-button @click="$router.back()">返回上页</el-button>
              <el-button type="primary" @click="$router.push('/')">返回首页</el-button>
            </el-space>
          </template>
        </el-result>
      `
    };

    // 主应用组件
    const App = {
      template: `
        <el-container style="min-height: 100vh;">
          <!-- 头部导航 -->
          <el-header>
            <el-menu :default-active="$route.path" mode="horizontal">
              <el-menu-item index="/" @click="$router.push('/')">
                <el-icon><House /></el-icon>
                首页
              </el-menu-item>
              <el-menu-item index="/about" @click="$router.push('/about')">
                <el-icon><InfoFilled /></el-icon>
                关于
              </el-menu-item>
              <el-menu-item index="/products" @click="$router.push('/products')">
                <el-icon><Goods /></el-icon>
                商品
              </el-menu-item>
              <el-menu-item index="/redirect-info" @click="$router.push('/redirect-info')">
                <el-icon><Right /></el-icon>
                重定向
              </el-menu-item>
              
              <div style="flex: 1;"></div>
              
              <!-- 状态显示 -->
              <div style="display: flex; align-items: center; margin-right: 20px;">
                <span style="margin-right: 10px;">当前状态:</span>
                <el-tag :type="getStatusTagType()">
                  {{ authState.getStatusText() }}
                </el-tag>
              </div>
            </el-menu>
          </el-header>

          <!-- 主要内容 -->
          <el-main>
            <!-- 路由信息 -->
            <el-alert 
              :title="getRouteInfo()" 
              type="info" 
              :closable="false"
              style="margin-bottom: 20px;"
            />

            <!-- 页面内容 -->
            <router-view></router-view>
          </el-main>
        </el-container>
      `,
      computed: {
        authState() {
          return authState;
        }
      },
      methods: {
        getStatusTagType() {
          if (!authState.isLoggedIn) return 'info';
          return authState.isAdmin ? 'danger' : 'success';
        },
        getRouteInfo() {
          let info = `当前路由: ${this.$route.path}`;
          if (Object.keys(this.$route.params).length > 0) {
            info += ` | 参数: ${JSON.stringify(this.$route.params)}`;
          }
          if (Object.keys(this.$route.query).length > 0) {
            info += ` | 查询: ${JSON.stringify(this.$route.query)}`;
          }
          if (this.$route.meta.from) {
            info += ` | 来源: ${this.$route.meta.from}`;
          }
          return info;
        }
      }
    };

    // 路由配置
    const routes = [
      { path: '/', component: Home },
      { 
        path: '/about', 
        component: About,
        beforeEnter: (to, from, next) => {
          // 检查是否来自重定向
          if (from.path === '/redirect-test') {
            to.meta.from = '重定向';
          }
          next();
        }
      },
      { path: '/redirect-info', component: RedirectInfo },
      {
        path: '/user/:id',
        component: UserDetail,
        children: [
          { path: 'profile', component: UserProfile },
          { path: 'settings', component: UserSettings }
        ]
      },
      { path: '/products', component: Products },
      { path: '/dashboard', component: Dashboard, meta: { requiresAuth: true } },
      { path: '/admin', component: Admin, meta: { requiresAuth: true, requiresAdmin: true } },
      {
        path: '/lazy',
        component: () => {
          return new Promise(resolve => {
            ElMessage.info('正在加载页面,请稍候...');
            setTimeout(() => resolve(LazyPage), 2000);
          });
        }
      },
      // 重定向路由 - 更明显的重定向逻辑
      { 
        path: '/redirect-test', 
        redirect: to => {
          ElMessage.success('重定向成功: /redirect-test → /about');
          return '/about';
        }
      },
      { 
        path: '/old-dashboard', 
        redirect: '/dashboard'
      },
      { 
        path: '/legacy-admin', 
        redirect: '/admin'
      },
      { path: '/:pathMatch(.*)*', component: NotFound }
    ];

    // 创建路由
    const router = createRouter({
      history: createWebHashHistory(),
      routes
    });

    // 路由守卫 - 改进的守卫逻辑
    router.beforeEach((to, from, next) => {
      console.log('=== 路由守卫检查 ===');
      console.log('从:', from.path, '到:', to.path);
      console.log('登录状态:', authState.isLoggedIn);
      console.log('管理员状态:', authState.isAdmin);
      console.log('路由元信息:', to.meta);
      
      // 检查是否需要登录
      if (to.meta.requiresAuth && !authState.isLoggedIn) {
        ElMessage.error('🔒 请先登录才能访问此页面!');
        console.log('❌ 访问被拒绝: 需要登录');
        next('/');
        return;
      }
      
      // 检查是否需要管理员权限
      if (to.meta.requiresAdmin && (!authState.isLoggedIn || !authState.isAdmin)) {
        if (!authState.isLoggedIn) {
          ElMessage.error('🔒 请先登录!');
          console.log('❌ 访问被拒绝: 需要登录');
        } else {
          ElMessage.error('🔒 需要管理员权限才能访问此页面!');
          console.log('❌ 访问被拒绝: 需要管理员权限');
        }
        next('/');
        return;
      }
      
      console.log('✅ 路由守卫通过');
      next();
    });

    // 路由后置守卫 - 记录访问日志
    router.afterEach((to, from) => {
      console.log(`✅ 路由跳转完成: ${from.path} → ${to.path}`);
    });

    // 创建应用
    const app = createApp(App);

    // 注册图标
    for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
      app.component(key, component);
    }

    app.use(ElementPlus);
    app.use(router);
    app.mount('#app');

    console.log('🚀 Vue Router 训练应用启动成功!');
  </script>
</body>
</html>
相关推荐
Z_ One Dream2 小时前
React 和 Vue 如何选择?(2026 年)
javascript·vue.js·react.js
用户6120414922132 小时前
jsp+servlet做的医院挂号看诊管理系统
java·javascript·mysql
二十雨辰2 小时前
vite快速上手
前端
Dxy12393102162 小时前
Python对图片进行加密,js前端进行解密
前端·javascript·python
支付宝体验科技2 小时前
SEE Conf 2025 来啦,一起探索 AI 时代的用户体验与工程实践!
前端
江城开朗的豌豆2 小时前
路由对决:Vue Router vs React Router,谁是你的菜?
前端·javascript·react.js
建群新人小猿2 小时前
客户标签自动管理:标签自动化运营,画像持久保鲜
android·java·大数据·前端·git
代码79722 小时前
【无标题】使用 Playwright 实现跨 Chromium、Firefox、WebKit 浏览器自动化操作
运维·前端·深度学习·华为·自动化
Zuckjet_2 小时前
第 5 篇:WebGL 从 2D 到 3D - 坐标系、透视与相机
前端·javascript·3d·webgl