学习SpringBoot+Vue前后端分离项目,原项目GitHub地址,项目作者江雨一点雨博客。
安装和使用Vuex
命令行输入npm install vuex
npm install vuex
创建src/store/index.js
import Vue from 'vue'
import Vuex from 'vuex' //导入Vuex
Vue.use(Vuex)
export default new Vuex.Store({
// 定义属性
state:{
//菜单信息存放
routes:[]
},
//修改属性
mutations:{
//调用时只需传data
initRoutes(state,data){
state.routes=data;
}
},
//Action类似于mutation
//Action 提交的是 mutation,而不是直接变更状态。
//Action 可以包含任意异步操作。
actions:{
}
})
在main.js中引入vuex
import store from './store/index.js'
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
菜单请求工具类封装
创建src/utils/menus.js
import {getRequest} from "./api";
//创建菜单初始化方法
export const initMenu=(router,store)=>{
//判断是否有菜单数据,有就不加载
if (store.state.routes.length>0){
return;
}
getRequest("/system/config/menu").then(data=>{
if (data){
let fmtRoutes = formatRoutes(data);
router.addRoutes(fmtRoutes);
store.commit('initRoutes',fmtRoutes)
}
})
}
export const formatRoutes=(routes)=>{
let fmRoutes=[];
routes.forEach(router=>{
//批量定义,相当于let path=router.path
let {
path,
component,
name,
meta,
iconCls,
children //此处的children已经格式化了
}=router;
//判断是否是一级菜单的children
if (children && children instanceof Array){
//递归
children=formatRoutes(children);
}
let fmRouter={
path:path,
name:name,
iconCls:iconCls,
meta:meta,
children:children,
//动态加载
component(resolve){
//Home开头
if (component.startsWith("Home")) {
require(['../views/' + component + '.vue'], resolve);
}else if (component.startsWith("Emp")){
require(['../views/emp/' + component + '.vue'], resolve);
}else if (component.startsWith("Per")){
require(['../views/per/' + component + '.vue'], resolve);
}else if (component.startsWith("Sal")){
require(['../views/sal/' + component + '.vue'], resolve);
}else if (component.startsWith("Sta")){
require(['../views/sta/' + component + '.vue'], resolve);
}else if (component.startsWith("Sys")){
require(['../views/sys/' + component + '.vue'], resolve);
}
}
}
//fmRouter放入数组fmRoutes中
fmRoutes.push(fmRouter);
})
return fmRoutes;
}
根据数据库中menu表创建包和文件,重复性工作。
部署路由导航守卫
为了解决加载菜单信息一刷新就消失的问题(其实是initMenus就加载一次),部署路由导航守卫
vue官网文档
需要全局部署,放到main.js中
router.beforeEach((to, from, next) => {
//判断要跳转的页面是否是登录页
if (to.path=='/'){
next();
}else {
initMenu(router,store);
next();
}
})
在Home.vue中添加computed属性
computed:{
routes(){
return this.$store.state.routes;
}
},
修改el-submenu,因为routes已经在computed里面了。
<el-submenu :index="index+''" v-for="(item,index) in routes" v-if="!item.hidden" :key="index">
现在有一个小问题需要修改,当我们注销登录后,换另外一个用户登录,显示的还是上一个用户的菜单信息,刷新后才显示正确的信息。这是因为在注销登录时,没有清空store里面的信息。做如下修改,
commandHandler(cmd){
if (cmd == 'logout'){
this.$confirm('此操作将注销登录, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.getRequest("/logout");
window.sessionStorage.removeItem("user");
this.$store.commit('initRoutes',[]);//清空
this.$router.replace("/");
}).catch(() => {
this.$message({
type: 'info',
message: '已取消操作'
});
});
}
}
首页完善
在首页添加面包屑:显示当前页面的路径,快速返回之前的任意页面。
直接从element-ui官网复制粘贴,修改代码
<el-main>
//如果当前为home页则不显示面包屑,否则继续
<el-breadcrumb separator-class="el-icon-arrow-right" v-if="this.$router.currentRoute.path!='/home'">
<el-breadcrumb-item :to="{ path: '/home' }">首页</el-breadcrumb-item>
//获取当前路由的name属性
<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 class="homeRouterView"/>
</el-main>
添加homeWelcone样式
.homeWelcome{
text-align: center;
font-size: 30px;
font-family: 微软雅黑;
color: darkorange;
padding-top: 50px;
}