Vue3+Element Plus的简易后台管理系统(2):路由&Pinia

路由

src/router/index.ts:

import { createRouter, createWebHashHistory } from 'vue-router'
import { useTokenStore } from '@/stores/token'
import Login from '@/views/Login.vue'
import Index from '@/views/Index.vue'
import TheWelcome from '@/components/TheWelcome.vue'
import Dashboard from '@/views/Dashboard.vue'
import User from '@/views/User.vue'

const router = createRouter({
  history: createWebHashHistory(),
  routes: [
    { path: '/login', name:'Login',component: Login },
    {
      path: '/', component: Index, redirect: { name: 'Dashboard' },
      children: [
        { path: 'dashboard', name: 'Dashboard', component: Dashboard, meta: { requiresAuth: true } },
        { path: 'user', name: 'User', component: User ,meta: { requiresAuth: true }},
        { path: 'welcome', name: 'TheWelcome', component: TheWelcome }//瞎写的,展示冗余
      ]
    },
    // 404页面统一重定向至仪表盘组件
    {
      path: '/:pathMatch(.*)*',
      redirect: '/dashboard'
    }
  ],
})

router.beforeEach((to, from, next) => {
  const tokenStore = useTokenStore();
  tokenStore.initToken(); // 初始化 token

  // 场景1:需认证但未登录 → 跳登录页
  if (to.meta.requiresAuth && !tokenStore.hasToken) {
    next({ name: 'Login' });
  } 
  // 场景2:已登录时访问登录页 → 重定向至首页
  else if (to.name === 'Login' && tokenStore.hasToken) {
    next({ name: 'Dashboard' });
  } 
  // 场景3:其他情况放行
  else {
    next();
  }
});

export default router
  • 404页面统一重定向至仪表盘组件。
  • 添加一个全局导航守卫,实现路由控制&登录状态、权限的管理与校验。
  • 子路由。还记得之前讲路由的文章里,我特别提到要注意一下子路由,这里就用到了(Vue3开发极简入门(10):路由&嵌套路由)。
  • Index.vue的主布局使用嵌套子路由,就是将功能组件的页面展示放在MainLayout.vue的第二个RouterView内。如果不这么配置,其页面就会使用App.vue的第一个RouterView,这样就没有Title区和菜单区了(具体代码在下篇文章)。

Pinia

src/stores/token.ts:

import { defineStore } from 'pinia';
import { ref, computed } from 'vue';
import { type MenuItem } from '@/params'
import { getIconComponent } from '@/utils/icons'


export const useTokenStore = defineStore('token', () => {
    const token = ref('')
    const loginName = ref('')
    // 定义菜单数据
    const menuItems = ref<MenuItem[]>([])

    const hasToken = computed(() => token.value.trim() !== '')
    const currentUserName = computed(() => loginName.value)
    const currentMenuItems = computed(() => menuItems.value)

    const loginSuccess = (newToken: string, newLoginName: string, newMenuItems: MenuItem[]) => {
        console.log('登录成功:', newToken, newLoginName);

        token.value = newToken
        loginName.value = newLoginName
        menuItems.value = transformMenuIcons(newMenuItems)

        //存储在LocalStorage中
        localStorage.setItem("leoorgtoken", newToken)
        localStorage.setItem("leoorgloginname", newLoginName)
        localStorage.setItem("leoorgmenuitems", JSON.stringify(menuItems.value))
    }

    const logoutSuccess = () => {
        token.value = ''
        loginName.value = ''
        menuItems.value = []
        //清除LocalStorage
        localStorage.removeItem("leoorgtoken")
        localStorage.removeItem("leoorgloginname")
        localStorage.removeItem("leoorgmenuitems")
    }

    /**
     * 初始化Token
     * 如果有现成的token、loginName和menuItems,则直接返回。
     * 否则从LocalStorage中获取(如果存在的话)
     * @returns void
     */
    const initToken = () => {
        if (token.value && loginName.value && menuItems.value.length > 0) {
            return;
        }
        const tokenFromLocalStorage = localStorage.getItem('leoorgtoken');
        const loginNameFromLocalStorage = localStorage.getItem('leoorgloginname');
        const menuItemsFromLocalStorage = localStorage.getItem('leoorgmenuitems');

        if (tokenFromLocalStorage && loginNameFromLocalStorage && menuItemsFromLocalStorage) {
            token.value = tokenFromLocalStorage
            loginName.value = loginNameFromLocalStorage
            menuItems.value = JSON.parse(menuItemsFromLocalStorage)
        }
    }

    // 递归转换菜单图标
    const transformMenuIcons = (menus: MenuItem[]): MenuItem[] => {
        return menus.map(menu => ({
            ...menu,
            iconComponent: getIconComponent(menu.icon || ''),
            children: menu.children ? transformMenuIcons(menu.children) : []
        }))
    }

    return {
        token,
        currentUserName,
        currentMenuItems,
        loginName,
        hasToken,
        loginSuccess,
        logoutSuccess,
        initToken
    }
}) 

跟之前基本一样(Vue3开发极简入门(20):聚焦式状态管理库Pinia),就是处理了一下菜单列表。

© 版权声明

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
none
暂无评论...