在vue中向data数组添加数据_VUE学习笔记——导航菜单制作
导航菜单存储sessionStorage允许在浏览器中以KEY:VALUE形式存储响应数据,当前页面关闭后sessionStorage中存储的数据被清除。sessionStorage.setItem(key,value);//在sessionStorage中存储数据sessionStorage.getItem(key);//从sessionStorage中读取数据localStorage...
导航菜单存储
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('/');
更多推荐
所有评论(0)