2 12.根据菜单动态添加路由

  • 保存路由信息

const store = createStore({
    state() {
        return {

            ...

            // 
            menus: [],
            ruleNames: []
        }
    },
    mutations: {
        
        ...

        // 菜单相关
        SET_MENUS(state, menus){
            state.menus = menus
        },
        
        SET_RULENAMES(state, ruleNames){
            state.ruleNames = ruleNames
        },
    },
    actions: {

    	...

        // 获取当前登录用户信息
        getinfo({ commit }){
            return new Promise((resolve, reject) => {
                getinfo().then(res=>{
                    // console.log(res)
                    commit('SET_USERINFO', res)
                    commit('SET_MENUS', res.menus)
                    commit('SET_RULENAMES', res.ruleNames)
                    resolve(res)
                }).catch(err=>reject(err))
            })
        },
    }
})
  • 动态路由匹配设置

src/router/index.js

import {
    createRouter,
    createWebHashHistory
} from 'vue-router'

import Admin from '~/layouts/admin.vue'
import Index from '~/pages/index.vue'
import GoodList from '~/pages/goods/list.vue'
import CateGoryList from '~/pages/category/list.vue'
import NotFound from '~/pages/404.vue'
import Login from '~/pages/login.vue'


// 默认路由,所有用户共享
const routes = [
    { path: "/", name: "admin",component: Admin },
    { path: "/login", component: Login,  meta: {'title': '登录'}},
    { path: '/:pathMatch(.*)*', name: 'NotFound', component: NotFound, meta: {'title': '404'} },
]



// 动态路由,用户匹配菜单动态添加路由
const asyncRoutes = [
    { path:"/", name: "/",component: Index, meta:{ title:"后台首页" }},
    { path:"/goods/list",name:"/goods/list", component: GoodList, meta:{ title:"商品列表" }},
    { path:"/category/list", name:"/category/list",component: CateGoryList, meta:{ title:"分类列表" }}
]

// 3.创建路由实例并传递 `routes` 配置
export const router = createRouter({
    history: createWebHashHistory(),
    routes
}) 


// 动态添加路由的方法,根据路径配置
export function addRoutes(menus) {
    let hasNewRoutes = false
    const findAndAddRoutesByMenus = (arr) => {
        arr.forEach(e=>{
            let item = asyncRoutes.find(o=>o.path == e.frontpath)
            if (item && !router.hasRoute(item.path)){
                router.addRoute('admin',item)
                hasNewRoutes = true
            }

            if(e.child && e.child.length > 0) {
                findAndAddRoutesByMenus(e.child)
            }
        });
    }

    findAndAddRoutesByMenus(menus)
    // console.log(router.getRoutes())
    return hasNewRoutes
}
  • 全局前置守卫设置路由

src/permission.js

import { router, addRoutes }  from './router'
import { getToken } from '~/composables/auth'
import { toast,showFullLoading,hideFullLoading } from '~/composables/util'
import store from '~/store'


// 全局前置守卫
router.beforeEach(async (to, from, next) => {

    showFullLoading()

    const token = getToken()
    
    // 没有登录,强制跳转到登录页面
    if(!token && to.path != '/login') {
        toast('请先登录', 'error')
        return next({ path: "/login"})
    }


    // 防止重复登录
    if(token && to.path == '/login'){
        return next({ path: from.path ? from.path: '/'})
    }

    // 如果用户登录了,自动获取用户信息,并存储再 vuex 当中
    let hasNewRoutes = false
    if(token){
        let { menus } = await store.dispatch("getinfo")
        hasNewRoutes = addRoutes(menus)
    }


    // 设置页面标题
    let title = (to.meta.title ? to.meta.title : "") + "~牛皮编程后台"
    document.title = title

    
    hasNewRoutes ? next(to.fullPath) : next()
  })


router.afterEach((to,from)=> hideFullLoading())

Last updated