目录
在element中搜布局
<el-container>
<el-header>Header</el-header>
<el-container>
<el-aside width="200px">Aside</el-aside>
<el-main>Main</el-main>
</el-container>
</el-container>
复制到home中
再编写一些样式
<template>
<el-container class="home-container">
<!-- 头部区域 -->
<el-header>
<div>
<img src="../assets/heima.png" alt="">
<span>电商后台管理系统</span>
</div>
<el-button type="info" @click="logout">退出</el-button>
</el-header>
<!-- 页面主题区域 -->
<el-container>
<!-- 侧边栏 -->
<el-aside width="200px">
<el-menu background-color="#545c64" text-color="#fff" active-text-color="#ffd04b">
<!-- 一级菜单 -->
<el-submenu index="1">
<!-- 一级菜单的模版区域 -->
<template slot="title">
<!-- 图标 -->
<i class="el-icon-location"></i>
<!-- 文本 -->
<span>导航一</span>
</template>
<!-- 二级菜单 -->
<el-menu-item index="1-4-1">
<template slot="title">
<!-- 图标 -->
<i class="el-icon-location"></i>
<!-- 文本 -->
<span>导航一</span>
</template>
</el-menu-item>
</el-submenu>
</el-menu>
</el-aside>
<!-- 右侧内容 -->
<el-main>Main</el-main>
</el-container>
</el-container>
</template>
<script>
export default {
methods: {
logout() {
//清空token
window.sessionStorage.clear();
//跳转到登录页
this.$router.push("/login")
}
}
}
</script>
<style lang="less" scoped>
.home-container {
height: 100%;
}
.el-header {
background-color: #373d41;
display: flex;
justify-content: space-between;
padding-left: 0;
align-items: center;
color: #fff;
font-size: 20px;
>div {
display: flex;
align-items: center;
span {
margin-left: 15px;
}
}
}
.el-asider {
background-color: #322744;
}
.el-main {
background-color: #eaedf1;
}
</style>
并在element中引入
import Vue from 'vue'
import { Menu,Submenu,MenuItemGroup,MenuItem, Button, Form, FormItem, Input, Message ,Container,Header,Aside,Main} from 'element-ui'
Vue.use(Button)
Vue.use(Form)
Vue.use(FormItem)
Vue.use(Input)
Vue.use(Message)
Vue.use(Container)
Vue.use(Header)
Vue.use(Aside)
Vue.use(Main)
Vue.use(Menu)
Vue.use(Submenu)
Vue.use(MenuItemGroup)
Vue.use(MenuItem)
Vue.prototype.$message = Message
一。接口获取菜单数据
通过axios请求拦截器添加token,保证有获取数据的权限。
请求拦截器是一个预处理过程,为请求拦截器对象挂载一个token属性
找到配置请求的根路径
request就是一个请求的拦截器,通过use回调函数对请求拦截器挂载一个回调函数,把请求头做一个预处理,在use函数中接受一个config(请求对象)包含了好多属性,可以先打印看一下,在最后必须return config
axios.defaults.baseURL='http://127.0.0.1:8888/api/private/v1/'
axios.interceptors.request.use(config =>{
console.log(config)
//在最后必须return config
return config
})
登录后打印出一个对象
headers就是请求头
需要给请求头挂载一个token对象
config.headers.Authorization = window.sessionStorage.getItem('token')
再次登录后有Authorization,虽然是null,在主页进行点击的时候会有值
有权限的API就可以正常挂载成功了
二。发起请求获取左侧菜单数据
在home中页面加载的时候就应该获取到左侧菜单,所以在home的行为区定义一个生命周期函数
export default {
created() {
//调用getMenuList来获取所有的左侧菜单,在下面的方法中去定义
this.getMenuList()
},
methods: {
//获取所有的菜单,因为get函数返回值是一个promist,为了简化操作,加一个await
async getMenuList() {
//通过解构赋值把data属性解构出来,并重命名为res
const { data: res } = await this.$http.get('menus')
console.log(res)
}
}
重新登录打印出来
可以成功拿到后台数据,接下来应该在页面中进行渲染出来
把取到的数据立即挂载到data中
data(){
return{
//左侧菜单数据
menulist:[]
}
},
接下来进行赋值
先判断,如果获取失败,返回错误消息,一定是在meta上面存着
如果成功,进行赋值,
async getMenuList() {
//通过解构赋值把data属性解构出来,并重命名为res
const { data: res } = await this.$http.get('menus')
// 可以成功获取到后台的数据,对数据进行赋值,先在data中创建新数组
if (res.meta.status !== 200) return this.$message.error(res.meta.msg)
this.menulist = res.data
console.log(res)
}
这样就把获取到的菜单数据成功保存到了menu-list中
三。绘制到页面中
需要来两个双层的循环
每一个v-for都尽量提供唯一的key值
<el-submenu :index="1" v-for ="item in menulist" :key="item.id">
<span>{{item.authName}}</span>
四、设置菜单单独展开
所有每一个菜单都需要一个独属于自己的值,动态数据绑定index="item.id"
但是会报错,因为index只接受字符串,不接受具体的数值,怎么把数值变成字符串呢
最简单的就是添加一个空字符串。注意这里更改后index前面要加冒号。
接下来渲染二级菜单
<el-menu-item :index="subItem.id + ''" v-for="subItem in item.children">
<template slot="title">
<!-- 图标 -->
<i class="el-icon-location"></i>
<!-- 文本 -->
<span>{{subItem.authName}}</span>
五,点开后用户列表的高亮显示更改
在侧边菜单栏区域直接替换掉单击激活的颜色
active-text-color="#00AEEC"
更改图标
所有的一级菜单图标都是不一样的
因为在element图标是有限的,所以用到图标库
如何按照顺序把图标加进来呢,
先定义一个图标对象,花括号里以对应的菜单id指向字体的类名。
data() {
return {
//左侧菜单数据
menulist: [],
iconsObj: {
'125':'iconfont icon-users',
'103':'iconfont icon-tijikongjian',
'101':'iconfont icon-shangpin',
'102':'iconfont icon-baobiao',
'145':'iconfont icon-danju',
}
}
},
这样所有图标的对象就建立好了,在进行循环的时候,每循环一次生成一个一级菜单,每次循环都有这个ID,根据id,对应的类取出来加到这个循环中、
<i :class="iconsObj[item.id]"></i>
图标和文本之间有间距,
因为每个图标都有一个类,叫iconfont
在底部定义一个类名
.iconfont{
margin-right: 10px;
}
六。每次只能展开一个二级菜单
点击另外的二级菜单的时候,这个会缩进去,只能同时展示一个。
用到element中的一个属性:unique-opened ="true
<el-menu background-color="#545c64" text-color="#fff" active-text-color="#00AEEC" :unique-opened ="true">
七,对齐菜单栏
去掉边框线即可
.el-menu {
border-right: none;
}
不能像视频里写在aside里面,会去不掉
八,左侧菜单栏的折叠和展开
放一个div,通过折叠按钮进行折叠和展开
<div class="toggle-button">|||</div>
然后给类名加相关的样式
.toggle-button {
//加一个背景色,文本居中
background-color: #9499A0;
font-size: 10px;
line-height: 24px;
color: #fff;
text-align: center;
//增加文本之间的间距
letter-spacing: 0.2em;
//鼠标放上去是一个手
cursor: pointer;
}
折叠展开 加一个单击事件
<div class="toggle-button" @click="toggleCollapse">|||</div>
加一个属性
:unique-opened="true" :collapse="true">
在data在设定默认为不折叠
//菜单栏是否折叠,默认不折叠
isCollapse:false
动态更改: :collapse=" isCollapse">
单击时进行布尔值的切换,在函数中进行取反。
//点击按钮切换菜单的折叠和展开
toggleCollapse(){
this.isCollapse =! this.isCollapse
}
然后关闭默认的动画效果,因为动画太丑了,找到属性:collapse-transition="false"
:unique-opened="true" :collapse=" isCollapse" collapse-transition="false">
缩小的时候同时改变侧边栏大小
<el-aside :width="isCollapse ? '64px':'200px'">
九, 在登录后自动到welcome页面
新建一个welcome组件
因为是home的子组件,所以需要这样写
{
path:'/home',
component: Home ,
redirect:'/welcome',
children:[{path:'/welcome',component:Welcome }]
}
在右侧主题进行路由占位符
<el-main>
<!-- 路由占位符 -->
<router-view></router-view>
</el-main>
十。左侧菜单栏改为路由链接形式
点击可以跳转到空白页面
需要在侧边栏菜单区域开启路由模式
想要每次点二级菜单的时候都跳转到路由地址中
通过index属性当做跳转地址
由于path么有斜线,所以要加上斜线
<el-menu-item :index="'/'+ subItem.path" v-for="subItem in item.children">
十一。创建用户列表主页
children:[
{path:'/welcome',component:Welcome},
{path:'/users',component:Users},
],
十二,当页面切换回用户列表时,高亮仍跟着显示
1.先设定一个固定的高亮,然后再变成动态的
default-active="/users"
2,动态:点击链接的时候,把对应的地址先保存到session中
当下次刷新页面的时候,就动态的取出来复制给左
created() {
//调用getMenuList来获取所有的左侧菜单,在下面的方法中去定义
this.getMenuList()
this.activePath=window.sessionStorage.getItem('activePath')
},
侧的菜单
找到二级菜单,绑定单击事件
保存链接的状态
<!-- 二级菜单 -->
<el-menu-item :index="'/'+ subItem.path" v-for="subItem in item.children" :key="subItem.id" @click="savaNavState('/'+subItem.path)">
在data中写
//被激活的链接地址
activePath:''
在方法中写
created() {
//调用getMenuList来获取所有的左侧菜单,在下面的方法中去定义
this.getMenuList()
this.activePath=window.sessionStorage.getItem('activePath')
},