前端核心框架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>
相关推荐
fruge2 分钟前
前端正则表达式实战合集:表单验证与字符串处理高频场景
前端·正则表达式
baozj7 分钟前
🚀 手动改 500 个文件?不存在的!我用 AST 撸了个 Vue 国际化神器
前端·javascript·vue.js
用户40993225021216 分钟前
为什么Vue 3的计算属性能解决模板臃肿、性能优化和双向同步三大痛点?
前端·ai编程·trae
海云前端116 分钟前
Vue首屏加速秘籍 组件按需加载真能省一半时间
前端
蛋仔聊测试18 分钟前
Playwright 中route 方法模拟测试数据(Mocking)详解
前端·python·测试
零号机29 分钟前
使用TRAE 30分钟极速开发一款划词中英互译浏览器插件
前端·人工智能
molly cheung1 小时前
FetchAPI 请求流式数据 基本用法
javascript·fetch·请求取消·流式·流式数据·流式请求取消
疯狂踩坑人1 小时前
结合400行mini-react代码,图文解说React原理
前端·react.js·面试
Mintopia1 小时前
🚀 共绩算力:3分钟拥有自己的文生图AI服务-容器化部署 StableDiffusion1.5-WebUI 应用
前端·人工智能·aigc
街尾杂货店&1 小时前
CSS - transition 过渡属性及使用方法(示例代码)
前端·css