Vue2项目练手——通用后台管理项目
- 菜单权限功能
- tab.js
- Login.vue
- CommonAside.vue
- router/index.js
- 权限管理问题解决
- router/tab.js
- CommonHeader.vue
- main.js
菜单权限功能
- 不同的账号登录,会有不同的菜单权限
- 通过url输入地址来显示页面
- 对于菜单的数据在不同页面之间的数据通信
tab.js
import Cookie from "js-cookie";
export default {
state:{
menu:[]
},
mutations:{
//设置menu的数据
setMenu(state,val){
state.menu=val
console.log("val",val)
Cookie.set('menu',JSON.stringify(val))
},
//动态注册路由
addMenu(state,router){
//判断缓存中是否有数据
if(!Cookie.get('menu')) return
const menu=JSON.parse(Cookie.get('menu'))
state.menu=menu
//组装动态路由的数据
const menuArray=[]
menu.forEach(item=>{
if(item.children){
item.children= item.children.map(item=>{
item.component=()=>import(`../pages/${item.url}`)
return item
})
menuArray.push(...item.children)
}else{
item.component=()=>import(`../pages/${item.url}`)
menuArray.push(item)
}
})
console.log("menuArray",menuArray)
//路由的动态添加
menuArray.forEach(item=>{
router.addRoute('main',item)
})
console.log("menuArray",menuArray)
}
}
全部代码:
import Cookie from "js-cookie";
export default {
state:{
isCollapse:false, //控制菜单的展开还是收起
tabsList:[
{
path:'/',
name:"home",
label:"首页",
icon:"s-home",
url:'Home/Home'
},
], //面包屑数据
menu:[]
},
mutations:{
// 修改菜单展开收起的方法
collapseMenu(state){
state.isCollapse=!state.isCollapse
},
//更新面包屑
selectMenu(state,val){
//判断添加的数据是否为首页
if(val.name!=='home'){
// console.log("state",state)
const index=state.tabsList.findIndex(item=>item.name===val.name)
//如果不存在
if(index===-1){
state.tabsList.push(val)
}
}
},
//删除指定的tag
closeTag(state,item){
const index=state.tabsList.findIndex(val=>val.name===item.name)
state.tabsList.splice(index,1) //splice(删除的位置,删除的个数)
},
//设置menu的数据
setMenu(state,val){
state.menu=val
console.log("val",val)
Cookie.set('menu',JSON.stringify(val))
},
//动态注册路由
addMenu(state,router){
//判断缓存中是否有数据
if(!Cookie.get('menu')) return
const menu=JSON.parse(Cookie.get('menu'))
state.menu=menu
//组装动态路由的数据
const menuArray=[]
menu.forEach(item=>{
if(item.children){
item.children= item.children.map(item=>{
item.component=()=>import(`../pages/${item.url}`)
return item
})
menuArray.push(...item.children)
}else{
item.component=()=>import(`../pages/${item.url}`)
menuArray.push(item)
}
})
console.log("menuArray",menuArray)
//路由的动态添加
menuArray.forEach(item=>{
router.addRoute('main',item)
})
console.log("menuArray",menuArray)
}
}
}
Login.vue
getMenu(this.form).then(({data})=>{
console.log(data)
if(data.code===20000){
Cookie.set('token',data.data.token)
//获取菜单的数据,存入store中
this.$store.commit('setMenu',data.data.menu)
this.$store.commit('addMenu',this.$router)
//跳转到首页
this.$router.push('/home')
}else{
this.$message.error(data.data.message)
}
})
全部代码:
<template>
<div id="app">
<div class="main-content">
<div class="title">系统登录</div>
<div class="content">
<el-form label-width="70px" :inline="true" :model="form" status-icon :rules="rules" ref="ruleForm" class="demo-ruleForm">
<el-form-item label="用户名" prop="username">
<el-input v-model="form.username" placeholder="请输入账号"></el-input>
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input v-model="form.password" type="password" autocomplete="off" placeholder="请输入密码"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm('ruleForm')">登录</el-button></el-col>
</el-form-item>
</el-form>
</div>
</div>
</div>
</template>
<script>
// import Mock from 'mockjs'
import Cookie from 'js-cookie'
import {getMenu} from "@/api";
export default {
name: "login",
data(){
return{
form: {
username: '',
password:""
},
rules: {
username: [
{required: true, message: '请输入用户名', trigger: 'blur'},
],
password: [
{required:true,message:"请输入密码",trigger:"blur"}
]
}
}
},
methods:{
//登录
submitForm(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
//token信息
/*const token=Mock.Random.guid() //生成随机数
//token信息存入cookie用于不同页面间的通信
Cookie.set('token',token)*/
getMenu(this.form).then(({data})=>{
console.log(data)
if(data.code===20000){
Cookie.set('token',data.data.token)
//获取菜单的数据,存入store中
this.$store.commit('setMenu',data.data.menu)
this.$store.commit('addMenu',this.$router)
//跳转到首页
this.$router.push('/home')
}else{
this.$message.error(data.data.message)
}
})
} else {
console.log('error submit!!');
return false;
}
});
},
}
}
</script>
<style lang="less" scoped>
#app {
display: flex;
background-color: #333;
height: 100vh;
.main-content{
height: 300px;
width: 350px;
//line-height: 100vh;
background-color: #fff;
margin: 200px auto;
border-radius: 15px;
padding: 35px 35px 15px 35px;
box-sizing: border-box;
box-shadow: 5px 5px 10px rgba(0,0,0,0.5),-5px -5px 10px rgba(0,0,0,0.5);
.title{
font-size: 20px;
text-align: center;
font-weight: 300;
}
.content{
margin-top: 30px;
}
.el-input{
width: 198px;
}
.el-button{
margin-left: 105px;
}
}
}
</style>
CommonAside.vue
data() {
return {
};
},
menuData(){
//判断当前数据,如果缓存中没有,当前store中获取
return JSON.parse(Cookie.get('menu'))||this.$store.state.tab.menu
}
全部代码:
<template>
<el-menu default-active="1-4-1" class="el-menu-vertical-demo" @open="handleOpen" @close="handleClose"
:collapse="isCollapse" background-color="#545c64" text-color="#fff"
active-text-color="#ffd04b">
<h3>{{isCollapse?'后台':'通用后台管理系统'}}</h3>
<el-menu-item @click="clickMenu(item)" v-for="item in noChildren" :key="item.name" :index="item.name">
<i :class="`el-icon-${item.icon}`"></i>
<span slot="title">{{item.label}}</span>
</el-menu-item>
<el-submenu :index="item.label" v-for="item in hasChildren" :key="item.label">
<template slot="title">
<i :class="`el-icon-${item.icon}`"></i>
<span slot="title">{{item.label}}</span>
</template>
<el-menu-item-group>
<el-menu-item @click="clickMenu(subItem)" :index="subItem.path" :key="subItem.path" v-for="subItem in item.children">
{{subItem.label}}
</el-menu-item>
</el-menu-item-group>
</el-submenu>
</el-menu>
</template>
<style lang="less" scoped>
.el-menu-vertical-demo:not(.el-menu--collapse) {
width: 200px;
min-height: 400px;
}
.el-menu{
height: 100vh; //占据页面高度100%
h3{
color: #fff;
text-align: center;
line-height: 48px;
font-size: 16px;
font-weight: 400;
}
}
</style>
<script>
import Cookie from "js-cookie";
export default {
data() {
return {
};
},
methods: {
handleOpen(key, keyPath) {
console.log(key, keyPath);
},
handleClose(key, keyPath) {
console.log(key, keyPath);
},
clickMenu(item){
// console.log(item)
// console.log(this.$route.path)
// 当页面的路由与跳转的路由不一致才允许跳转
if(this.$route.path!==item.path && !(this.$route.path==='/home'&&(item.path==='/'))){
this.$router.push(item.path)
}
this.$store.commit('selectMenu',item)
}
},
mounted() {
// console.log(this.$route.path)
},
computed:{
//没有子菜单的数据
noChildren(){
return this.menuData.filter(item=>!item.children)
},
//有子菜单数组
hasChildren(){
return this.menuData.filter(item=>item.children)
},
isCollapse(){
return this.$store.state.tab.isCollapse
},
menuData(){
//判断当前数据,如果缓存中没有,当前store中获取
return JSON.parse(Cookie.get('menu'))||this.$store.state.tab.menu
}
}
}
</script>
router/index.js
{
// 子路由
name:"main",
path:'/',
redirect:"/home", //重定向 当路径为/,则重定向home
component:Main,
children:[
/*{
name:"user",
path:"user",
component:User,
meta:{title:"用户管理"}
},
{
name:"home",
path:"home",
component:Home,
meta:{title:"首页"}
},
{
name:"mall",
path:"mall",
component:Mall,
meta:{title:"商品管理"}
},
{
name:"page1",
path:"page1",
component:PageOne,
meta:{title:"页面1"}
},
{
name:"page2",
path:"page2",
component:PageTwo,
meta:{title:"页面2"}
}*/
]
}
全部代码:
import VueRouter from "vue-router";
import Login from "@/pages/Login.vue";
import Main from '@/pages/Main.vue';
import User from "@/pages/User.vue";
import Home from "@/pages/Home.vue";
import Mall from "@/pages/Mall.vue";
import PageOne from "@/pages/PageOne.vue";
import PageTwo from "@/pages/PageTwo.vue";
import Cookie from "js-cookie";
const router= new VueRouter({
// 浏览器模式设置,设置为history模式
// mode:'history',
routes:[
{
name:'login',
path:"/login",
component:Login,
meta:{title:"登录"},
},
{
// 子路由
name:"main",
path:'/',
redirect:"/home", //重定向 当路径为/,则重定向home
component:Main,
children:[
/*{
name:"user",
path:"user",
component:User,
meta:{title:"用户管理"}
},
{
name:"home",
path:"home",
component:Home,
meta:{title:"首页"}
},
{
name:"mall",
path:"mall",
component:Mall,
meta:{title:"商品管理"}
},
{
name:"page1",
path:"page1",
component:PageOne,
meta:{title:"页面1"}
},
{
name:"page2",
path:"page2",
component:PageTwo,
meta:{title:"页面2"}
}*/
]
}
]
})
//添加全局前置导航守卫
router.beforeEach((to,from,next)=>{
//判断token存不存在
const token=Cookie.get('token')
//token不存在,说明当前用户是未登录,应该跳转至登录页
if(!token&&to.name!=='login'){
next({name:'login'})
}else if(token && to.name=="login"){ //token存在,说明用户登录,此时跳转至首页
next({name:'home'})
}else{
next()
}
})
// 后置路由守卫
router.afterEach((to,from)=>{
document.title=to.meta.title||"通用后台管理系统"
})
export default router
权限管理问题解决
router/tab.js
clearTabs(state){
//清除除过首页之外的所有面包屑
state.tabsList=state.tabsList.splice(0,1)
}
全部代码:
import Cookie from "js-cookie";
export default {
state:{
isCollapse:false, //控制菜单的展开还是收起
tabsList:[
{
path:'/',
name:"home",
label:"首页",
icon:"s-home",
url:'Home/Home'
},
], //面包屑数据
menu:[]
},
mutations:{
// 修改菜单展开收起的方法
collapseMenu(state){
state.isCollapse=!state.isCollapse
},
//更新面包屑
selectMenu(state,val){
//判断添加的数据是否为首页
if(val.name!=='home'){
// console.log("state",state)
const index=state.tabsList.findIndex(item=>item.name===val.name)
//如果不存在
if(index===-1){
state.tabsList.push(val)
}
}
},
//删除指定的tag
closeTag(state,item){
const index=state.tabsList.findIndex(val=>val.name===item.name)
state.tabsList.splice(index,1) //splice(删除的位置,删除的个数)
},
//设置menu的数据
setMenu(state,val){
state.menu=val
console.log("val",val)
Cookie.set('menu',JSON.stringify(val))
},
//动态注册路由
addMenu(state,router){
//判断缓存中是否有数据
if(!Cookie.get('menu')) return
const menu=JSON.parse(Cookie.get('menu'))
state.menu=menu
//组装动态路由的数据
const menuArray=[]
menu.forEach(item=>{
if(item.children){
item.children= item.children.map(item=>{
item.component=()=>import(`../pages/${item.url}`)
return item
})
menuArray.push(...item.children)
}else{
item.component=()=>import(`../pages/${item.url}`)
menuArray.push(item)
}
})
console.log("menuArray",menuArray)
//路由的动态添加
menuArray.forEach(item=>{
router.addRoute('main',item)
})
console.log("menuArray",menuArray)
},
clearTabs(state){
//清除除过首页之外的所有面包屑
state.tabsList=state.tabsList.splice(0,1)
}
}
}
CommonHeader.vue
handleClick(command){
if(command==='cancel'){
console.log("登出")
//清除Cookie的token信息
Cookie.remove('token')
//清除cookie中的menu
Cookie.remove('menu')
this.$store.commit('clearTabs')
this.$router.push('/login')
}
}
全部代码:
<template>
<div class="header-container">
<div class="l-content">
<el-button style="margin-right: 20px" icon="el-icon-menu" size="mini" @click="handleMenu"></el-button>
<!-- 面包屑-->
<!-- <span class="text">首页</span>-->
<el-breadcrumb separator="/">
<el-breadcrumb-item v-for="item in tags" :key="item.path" :to="{ path: item.path }">{{ item.label }}</el-breadcrumb-item>
</el-breadcrumb>
</div>
<div class="r-content">
<el-dropdown @command="handleClick">
<span class="el-dropdown-link">
<img src="@/assets/user.webp" alt="">
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item>个人中心</el-dropdown-item>
<el-dropdown-item command="cancel">退出</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</div>
</template>
<script>
import {mapState} from 'vuex'
import Cookie from 'js-cookie'
export default {
name: "CommonHeader",
methods:{
handleMenu(){
this.$store.commit('collapseMenu')
},
handleClick(command){
if(command==='cancel'){
console.log("登出")
//清除Cookie的token信息
Cookie.remove('token')
//清除cookie中的menu
Cookie.remove('menu')
this.$store.commit('clearTabs')
this.$router.push('/login')
}
}
},
computed:{
...mapState({
tags: state=>state.tab.tabsList
})
}
}
</script>
<style scoped lang="less">
.header-container {
height: 60px;
background-color: #333;
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 20px;
.text {
color: #fff;
font-size: 14px;
margin-left: 10px;
}
.r-content{
img{
width: 40px;
height: 40px;
border-radius: 50%;
}
}
.l-content{
display: flex;
align-items: center;
/deep/.el-breadcrumb__item{ /*元素没有绑定data-v-5a90ec03这样的编号时候,样式不起作用,使用deep进行穿刺可解决问题*/
.el-breadcrumb__inner{
font-weight: normal;
&.is-link{
color: #666;
}
}
&:last-child{
.el-breadcrumb__inner {
color: #fff;
}
}
}
}
}
</style>
main.js
created(){
store.commit('addMenu',router)
}
全部代码:
import Vue from 'vue'
import App from './App.vue'
import VueRouter from "vue-router";
import router from "@/router";
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css'
import store from '@/store'
//引入mock模拟
import '@/api/mock'
Vue.config.productionTip = false
Vue.use(VueRouter)
Vue.use(ElementUI)
new Vue({
store,
router,
render: h => h(App),
created(){
store.commit('addMenu',router)
}
}).$mount('#app')
项目到此Vue2部分也就结束了