【微人事项目笔记】5、左边菜单栏前端页面开发,使用 vuex 存放数据
程序员文章站
2022-05-18 18:39:39
...
上一小节我们把查询menu的接口开发好了,那么这一小节就制作前端页面,把后台返回的数据展示出来。
后台返回的数据存放在vuex中,vuex中的数据是公共的,所有组件都可以访问到,另外vuex比sessionStorage相对安全。
1、安装vuex
npm install vuex
2、vuex的简单使用介绍
创建store.js,引入vuex,state中就是我们存放的数据,mutations中就是我们要改变数据的方法,改变 store 中的状态的唯一途径就是显式地提交 (commit) ,
Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此我们可以调用 context.commit 提交一个 mutation。在这里本项目直接使用store.commit(‘initRouters’, 参数)来调用mutation。
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
// 数据
state:{
routes:[]
},
// 定义的回调函数,用来变更数据状态
mutations:{
initRouters(state, data) {
state.routes = data
}
},
// 提交mutation中的函数
actions:{
}
})
和前面的api.js同样需要在main.js中引入,
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from "./utils/store";
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import {postKeyValueRequest, postRequest,putRequest, getRequest, deleteRequest} from "./utils/api";
Vue.prototype.postKeyValueRequest = postKeyValueRequest;
Vue.prototype.postRequest = postRequest;
Vue.prototype.putRequest = putRequest;
Vue.prototype.getRequest = getRequest;
Vue.prototype.deleteRequest = deleteRequest;
Vue.config.productionTip = false
Vue.use(ElementUI);
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
后面就可以使用store了。
3、封装接收后台menu数据工具menus.js
menus.js,主要工作就是请求后端接口获取menus数据放在router.js和store中,把component字符串转成对应的组件,其他的依然是字符串格式。
import {getRequest} from "./api";
export const initMenu=(router, store) => {
// 如果store中有数据 就直接返回
if (store.state.routes.length > 0) {
return;
}
getRequest("/system/config/menu").then(data=>{
if (data && data.obj) {
let fmtRouters = formatRouters(data.obj);
router.addRoutes(fmtRouters);
store.commit('initRouters', fmtRouters)
}
});
};
export const formatRouters = (routes) => {
let fmRouters = [];
routes.forEach(router=>{
let{path, component, name, children} = router;
if(children && children instanceof Array) {
children = formatRouters(children)
}
let fmRouter = {path:path,name:name,children:children,
// 把component字符串换成对应组件,动态导入
component(resolve){
require(['../views/'+component+'.vue'], resolve)
}
};
fmRouters.push(fmRouter)
});
return fmRouters;
};
4、导航守卫,initMenu初始化菜单何时执行?
如果用户刷新页面就要执行一次初始化菜单的话,那么每个页面都要有执行initMenu的代码,其实我们可以使用导航守卫,判断一下用户在跳转的时候是不是去了登录页面,否则的话就执行initMenu。
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from "./utils/store";
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import {postKeyValueRequest, postRequest, putRequest, getRequest, deleteRequest} from "./utils/api";
import {initMenu} from "./utils/menus";
Vue.prototype.postKeyValueRequest = postKeyValueRequest;
Vue.prototype.postRequest = postRequest;
Vue.prototype.putRequest = putRequest;
Vue.prototype.getRequest = getRequest;
Vue.prototype.deleteRequest = deleteRequest;
Vue.prototype.initMenu = initMenu;
Vue.config.productionTip = false
Vue.use(ElementUI);
// 导航守卫
router.beforeEach((to, from, next) => {
if (to.path == '/') { // 回登录页
next();
} else {
initMenu(router, store);
next();
}
});
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
Home.vue
<template>
<div>
<el-container class="homeContainer">
<el-header class="homeHeader">
<div class="title">微人事</div>
<el-dropdown class="userInfo" @command="handleCommand">
<span class="el-dropdown-link">
{{user.name}}<i><img :src="user.userface" alt="用户头像"></i>
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="userinfo">个人中心</el-dropdown-item>
<el-dropdown-item command="setting">设置</el-dropdown-item>
<el-dropdown-item divided command="logout">注销登录</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</el-header>
<el-container>
<el-aside width="200px">
<el-menu @select="menuClick">
<!-- 循环加载router中的children-->
<!-- <el-submenu index="1" v-for="(item, index) in this.$router.options.routes" v-if="!item.hidden">-->
<el-submenu index="1" v-for="(item, index) in routes" v-if="!item.hidden">
<template slot="title">
<i class="el-icon-location"></i>
<span>{{item.name}}</span>
</template>
<el-menu-item :index="child.path" v-for="(child, indexj) in item.children">{{child.name}}
</el-menu-item>
</el-submenu>
</el-menu>
</el-aside>
<el-main>
<el-breadcrumb separator-class="el-icon-arrow-right" v-if="this.$router.currentRoute.path!='/home'">
<el-breadcrumb-item :to="{ path: '/home' }">首页</el-breadcrumb-item>
<el-breadcrumb-item>{{this.$router.currentRoute.name}}</el-breadcrumb-item>
</el-breadcrumb>
<div class="homeWelcome" v-if="this.$router.currentRoute.path=='/home'">
欢迎来到微人事!
</div>
<router-view></router-view>
</el-main>
</el-container>
</el-container>
</div>
</template>
<script>
export default {
name: 'Home',
data() {
return {
user: JSON.parse(window.sessionStorage.getItem('user'))
}
},
computed:{
routes() {
return this.$store.state.routes;
}
},
methods: {
menuClick(index, indexPath) {
this.$router.push(index)
},
handleCommand(command) {
if (command == 'logout') {
this.$confirm('此操作将注销登录, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.getRequest('/logout')
window.sessionStorage.removeItem('user')
this.$router.replace('/')
}).catch(() => {
this.$message({
type: 'info',
message: '已取消操作'
});
});
}
}
}
}
</script>
<style>
.homeHeader {
background-color: #409eff;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0px 15px;
box-sizing: border-box;
}
.homeHeader .title {
font-size: 30px;
font-family: 华光行楷_CNKI;
color: #ffffff;
}
.homeHeader .userInfo {
cursor: pointer;
}
.el-dropdown-link img {
width: 48px;
height: 48px;
border-radius: 24px;
margin-left: 8px;
}
.el-dropdown-link {
display: flex;
align-items: center;
}
.homeWelcome{
text-align: center;
font-size: 30px;
color: #409eff;
}
</style>
5、测试
使用songjiang,123登录之后,把查询到的menu展示出来了。