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

* #### 保存路由信息

```js
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

```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

```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())
```

<div><img src="C:%5CUsers%5CAdministrator.DESKTOP-UK43ECI%5CAppData%5CRoaming%5Cmarktext%5Cimages%5C2023-02-21-19-16-59-image.png" alt=""> <figure><img src="/files/twOhFS2eDlsNPKNgndSO" alt=""><figcaption></figcaption></figure></div>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://close.gitbook.io/yun-wei-bi-ji/centos/vue/xiang-mu/2-12.-gen-ju-cai-dan-dong-tai-tian-jia-lu-you.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
