f1e30701b55aa242deac5ee64bbebee3.png

导航菜单存储

sessionStorage

允许在浏览器中以KEY:VALUE形式存储响应数据,当前页面关闭后sessionStorage中存储的数据被清除。

sessionStorage.setItem(key,value);//在sessionStorage中存储数据sessionStorage.getItem(key);//从sessionStorage中读取数据

localStorage

允许在浏览器中以KEY:VALUE形式存储响应数据,当前页面关闭后localStorage中存储的数据依然存在。无过期时间限制,直到手动删除localStorage中的数据。

localStorage.setItem(key,value);//在localeStorage中存储数据localStorage.getItem(key);//从localeStorage中读取数据localStorage.removeItem(key);//从localStorage中删除指定数据localStorage.clear();//清除localStorage中的所有数据

VUEX

通常的VUE组件中,包含视图(template),双向绑定的数据(data),方法(methods),以上三个属性都定义在同一个VUE组件中。视图(View)触发动作(Actions),动作(Actions)影响数据状态(state),数据状态(state)的变更导致更新视图(VIEW),在当前组件中形成闭环操作。当前组件触发动作只能操作当前组件数据,当前组件数据状态发生变更只能更新当前组件视图。无法实现多个组件通过动作操作同一个数据,同一个数据状态发生了变更影响多个组件的视图更新。

为了实现上述功能,我们需要将组件数据(data)抽取为全局数据(state),需要使用全局数据的组件都可以访问到全局数据,当中某个组件触发动作(mutations)使全局数据(state)发生更改,需要使用全局数据(state)的组件视图(view)也会发生更新。

VUE体系中使用VUEX来管理VUE组件需要使用的公共数据。因为导航菜单在VUE所有组件中都需要使用,所以将导航菜单响应数据通过VUEX的方式来进行存储。

VUEX在一个VUE工程中只能有一个全局实例对象(store)。store被称为仓库,用于保存需要使用的公共数据。任何组件都可以访问公共数据(state),也可以对公共数据进行修改(mutations)。

VUEX使用

VUEX安装

npm install vuex

VUEX配置项state

存储状态(需要操作的公共数据变量)。

mutations

提交状态修改。VUEX中唯一进行状态(state)修改的地方,非异步方式执行操作。

actions

提交状态修改(mutations),可以以异步方式执行操作。

getter

派生状态。作用等同于VUE组件的计算属性(computed)。

modules

store子模块,相当于store的实例。

保存菜单数据

store/index.js

import Vue from "vue"import Vuex from "vuex"//用以管理应用状态Vue.use(Vuex);export default new Vuex.Store({    state:{        //响应数据数组(菜单项)        routes:[]    },    mutations:{        /*          响应数据数组赋值          state:存储状态(可以不传)          data:响应数据          最多两个参数         */        initRoutes(state,data)        {          state.routes=data;        }    },    actions:{}})

加载菜单请求封装

utils/menus.js

import {getRequest} from "./api";/** * 实例化菜单项并赋值给公共数据 * @param router:VUE路由对象 * @param store: 仓库(用于保存公共数据) */export const initMenu = (router, store) => {    //如果仓库的状态(state)中的全局变量routes(保存导航菜单公共数据)的长度大于0,说明有导航菜单数据,无需发送请求    if (store.state.routes.length > 0) {        return;    }    getRequest("/system/menuInit/initMenu").then(data => {        if (data) {            let fmtRoutes = formatMenus(data);//获取格式化菜单项数组            router.addRoutes(fmtRoutes);//将格式化菜单项数组添加至VUE路由对象            store.commit('initMenu', fmtRoutes);//将格式化菜单项添加在共享数据            store.dispatch('connect');        }    })}/** * 格式化菜单项数据并添加至菜单项数组 * @param routes:响应菜单项数据 * @returns 格式化菜单项数组 */export const formatMenus = (menus) => {    let fmMenus = [];//格式化菜单项数组    menus.forEach(menu => {        //批量定义菜单项变量并赋值        let {            url,            path,            component,            name,            meta,            iconCls,            children        } = menu;        //如果包含子菜单属性并且子菜单属性类型为数组,进行递归调用        if (children && children instanceof Array) {            children = formatMenus(children);        }        //格式化VUE路由对象        let fmRouter = {            url:url,            path: path,            name: name,            iconCls: iconCls,            meta: meta,            children: children,            component(resolve) {                //使用require动态导入对应VUE组件对象(后端响应数据中component为字符串,此处应该拼接为VUE组件路径)                if (component.startsWith("Home")) {                    require(['../views/' + component + '.vue'], resolve);                } else if (component.startsWith("User")) {                    require(['../views/user/' + component + '.vue'], resolve);                } else if (component.startsWith("Basic")) {                    require(['../views/basic/' + component + '.vue'], resolve);                } else if (component.startsWith("System")) {                    require(['../views/system/' + component + '.vue'], resolve);                }             }        }        fmMenus.push(fmRouter);//菜单项格式化数组中添加格式化菜单项数据    })    return fmMenus;//返回格式化菜单项数组}

在util/menu.js中我们主要完成请求后端菜单项数据、格式化菜单项、将格式化后的菜单项数据添加至VUE路由(router)对象并赋值给共享数据相关功能。

请求后端菜单项数据

import {getRequest} from "./api";/** * 实例化菜单项并赋值给公共数据 * @param router:VUE路由对象 * @param store: 仓库(用于保存共享数据) */export const initMenu = (router, store) => {    //如果仓库的状态(state)中的全局变量routes(保存导航菜单共享数据)的长度大于0,说明有导航菜单数据,无需发送请求    if (store.state.routes.length > 0) {        return;    }    //发送请求获取导航菜单共享数据    getRequest("/system/menuConfig/initMenu").then(data => {        if (data) {         //对响应数据(导航菜单)进行格式化,添加至VUE路由(router)对象并赋值给共享数据        }    })}

格式化菜单项

在格式化菜单项的过程中,我们需要将后端响应数据中的component字符串转化为VUE组件对象,并动态导入VUE组件(无需在router/index.js中通过import导入相关VUE组件)。

/** * 格式化菜单项数据并添加至菜单项数组 * @param routes:响应菜单项数据 * @returns 格式化菜单项数组 */export const formatMenus = (menus) => {    let fmMenus = [];//格式化菜单项数组    menus.forEach(menu => {        //批量定义菜单项变量并赋值        let {            url,            path,            component,            name,            meta,            iconCls,            children        } = menu;        //如果包含子菜单属性并且子菜单属性类型为数组,进行递归调用        if (children && children instanceof Array) {            children = formatMenus(children);        }        //格式化VUE路由对象        let fmRouter = {            url:url,            path: path,            name: name,            iconCls: iconCls,            meta: meta,            children: children,            component(resolve) {                //使用require动态导入对应VUE组件对象(后端响应数据中component为字符串,此处应该拼接为VUE组件路径)                if (component.startsWith("Home")) {                    require(['../views/' + component + '.vue'], resolve);                } else if (component.startsWith("User")) {                    require(['../views/user/' + component + '.vue'], resolve);                } else if (component.startsWith("Basic")) {                    require(['../views/basic/' + component + '.vue'], resolve);                } else if (component.startsWith("System")) {                    require(['../views/system/' + component + '.vue'], resolve);                }             }        }        fmMenus.push(fmRouter);//菜单项格式化数组中添加格式化菜单项数据    })    return fmMenus;//返回格式化菜单项数组}

将菜单项数据添加至VUE路由对象,并赋值给共享变量

  getRequest("/system/menuConfig/initMenu").then(data => {        if (data) {            let fmtRoutes = formatMenus(data);//获取格式化菜单项数组            router.addRoutes(fmtRoutes);//将格式化菜单项数组添加至VUE路由对象(动态导入VUE组件)            store.commit('initMenus', fmtRoutes);//将格式化菜单项添加在共享数据            store.dispatch('connect');        }    })

导航菜单加载

初始化菜单时机

在将加载菜单请求封装完成后,我们需要调用initMenu函数进行菜单初始化,并对导航菜单进行渲染。通常情况下,我们会在登录成功后对initMenu函数进行调用,由于我们需要导航菜单在所有VUE组件中都需要进行使用,登录成功后调用initMenu函数菜单初始化加载成功,在登录成功后跳转的组件或其他VUE组件中按下F5或浏览器刷新按钮,initMenu函数不会在执行,导致导航菜单无法成功加载并初始化。此时需要引入VUE路由导航守卫机制。

路由导航守卫

导航指路由(vue路由对象组件间跳转)在发生改变。导航守卫用来对组件跳转的过程进行监听,并执行相关的操作。

此处需要使用全局前置守卫对组件路由进行监听。

/*全局导航守卫导航:表示路由信息正在发生改变导航守卫:导航开始变化到导航变化结束过程中,根据导航变化做出响应to:去哪里from:从哪来next:往下走 */router.beforeEach((to, from, next) => {    //目的地路径为'/'表示登出    if (to.path == '/') {        next();    }else {        /*           sessionStorage.getItem("user"):sessionStorage中存在登录用户信息         */        if(window.sessionStorage.getItem("user")){            initMenu(router,store);            next();        }        else        {            Message.error({message: '无法在未登录情况下对系统进行操作,请登录'});            //登录成功后重定向至未登录前浏览器请求路径            next('/?redirect='+to.path);        }    }})

初始化菜单

Home.vue

在登陆成功后跳转的组件中,通过计算属性(computed)定义的方法返回仓库中存在的共享数据,在组件中进行渲染。

 <el-menu router unique-opened>                        <el-submenu :index="index+''" v-for="(item,index) in routes" v-if="!item.hidden" :key="index">                            <template slot="title">                                <i style="color: #409eff;margin-right: 5px" :class="item.iconCls">i>                                <span>{{item.name}}span>                            template>                            <el-menu-item :index="child.path" v-for="(child,indexj) in item.children" :key="indexj">                                {{child.name}}                            el-menu-item>                        el-submenu>   el-menu>    //VUE实例中的计算属性  computed: {            routes() {                //返回Vuex中的共享菜单响应数据                return this.$store.state.routes;            }        },

执行登出操作时,需要对VUEX中的共享数据进行清空,否则切换登录用户(角色加载菜单不同)加载的还是共享数据中存储的菜单项。

 this.getRequest('/logout'); window.sessionStorage.removeItem('user');//从sessionStorage中移除当前登录用户信息 //登出时从仓库中清空菜单项 this.$store.commit('initMenu', []); this.$router.replace('/');
Logo

前往低代码交流专区

更多推荐