一、后台首页
1、首页布局
用于布局的容器组件,方便快速搭建页面的基本结构:
<el-container>
:外层容器。当子元素中包含 <el-header>
或 <el-footer>
时,全部子元素会垂直上下排列,否则会水平左右排列。
<el-header>
:顶栏容器。
<el-aside>
:侧边栏容器。
<el-main>
:主要区域容器。
<el-footer>
:底栏容器。
<template>
<el-container>
<!-- 侧边栏 -->
<el-aside width="220px">asider</el-aside>
<el-container>
<el-header>header</el-header>
<el-main>main</el-main>
</el-container>
</el-container>
</template>
2、顶部栏
<el-row type="flex" style="align-items:center">
<el-col :span="6">
<el-row>
<el-col :span="6">
<i class="el-icon-s-fold" style="font-size:24px" v-if="!isCollpase"></i>
<i class="el-icon-s-unfold" style="font-size:24px" v-else></i>
<i class="el-icon-refresh-left" style="font-size:24px"></i>
</el-col>
<el-col :span="18">
<el-breadcrumb separator="/" style="line-height:20px">
<el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
<el-breadcrumb-item>控制面板</el-breadcrumb-item>
<el-breadcrumb-item>工作台</el-breadcrumb-item>
</el-breadcrumb>
</el-col>
</el-row>
</el-col>
<el-col :span="4" :offset="14">
<el-row type="flex" style="align-items:center">
<el-col :span="8">
<el-avatar :size="45" src="https://woniuimage.oss-cn- hangzhou.aliyuncs.com/woniuimage/teacher/20220222/abc7a6e787be41d0b12aa41e429b71d2.png"
class="avatar"></el-avatar>
</el-col>
<el-col :span="8">个人中心</el-col>
<el-col :span="8">退出系统</el-col>
</el-row>
</el-col>
</el-row>
二、菜单栏
1、静态菜单
2、动态菜单
-
更改request.js文件
需要在请求拦截器中为头信息中添加Authorization
,它的值是从localStorage中获取的token的信息
axios.interceptors.request.use(config => {
config.headers.Authorization=localStorage.getItem('token')
return config
})
-
在api/modules/users.js文件中编写获取权限菜单的方法
export default{
getAuthMenus:()=>request.get('/menus/getAuthMenus')
}
-
在Home页面中,在created生命周期函数中调用获取权限菜单的方法
export default {
data(){
return{
menudata:[]
}
},
methods:{
async getAuthMenus(){
let result=await this.$api.users.getAuthMenus()
console.log(result);
this.menudata=result.data
}
},
created(){
this.getAuthMenus()
}
}
-
在页面中进行渲染
<el-menu
background-color="#202743"
text-color="#fff"
active-text-color="orange"
:unique-opened="true">
<!-- 使用v-for嵌套完成一二级菜单的渲染 -->
<el-submenu :index="item._id" v-for="item in menudata" :key="item._id">
<template slot="title">
<i :class="item.icon"></i>
<span>{{item.title}}</span>
</template>
<el-menu-item :index="subitem._id" v-for="subitem in item.children" :key="subitem._id">
<i :class="subitem.icon"></i>
<span slot="title">{{subitem.title}}</span>
</el-menu-item>
</el-submenu>
</el-menu>
3、路由鉴权
-
在api/modules/users.js文件中编写获取用户信息的api方法
import request from '@/api/request'
export default{
getUserInfo:()=>request.get('/users/getUserInfo')
}
-
在router/index.js中通过导航独享守卫完成路由鉴权
{
path:'/home',
component:()=>import('@/views/Home.vue'),
beforeEnter:async(to,from,next)=>{
//从localstroage获取token信息
let token=localStorage.getItem('token')
if(!token){
// Message.error('您还没有登录,请先登录')
Vue.prototype.$message.error('您还没有登录,请先登录')
router.replace('/login')
}else{
let result=await Vue.prototype.$api.users.getUserInfo()
if(result.code){
next()
}
}
}
}
-
在request.js文件中对于401错误进行处理
axios.interceptors.response.use(response => {
return response.data
}, ({ response }) => {
if (response) {
switch (response.status) {
case 401:
Message.error('您的token已失效,请重新登录')
router.replace('/login')
break
case 404:
break
case 500:
break
}
}
})
4、菜单的路由跳转
-
在Home.vue组件的
el-menu
中设置router="true"
<el-menu
background-color="#202743"
text-color="#fff"
active-text-color="orange"
:unique-opened="true"
:router="true">
</el-menu>
-
在el-menu下的
el-menu-item
中将index的值改为subItem.path
<el-menu-item :index="subitem.path" v-for="subitem in item.children" :key="subitem._id">
<i :class="subitem.icon"></i>
<span slot="title">{{subitem.title}}</span>
</el-menu-item>
-
在el-main中配置二级路由出口
<el-main>
<router-view></router-view>
</el-main>
-
在router/index.js中配置动态路由操作
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '@/views/Home.vue'
Vue.use(VueRouter)
const addRoutes=async(data)=>{
router.addRoute({
path:'/home',
component:Home,
children:data.map(item=>{
return{
path:item.path.substring(item.path.lastIndexOf("/")+1),
component:()=>import(`@/views${item.permission}.vue`)
}
})
})
}
const routes = [
{
path: '/login',
component: () => import('@/views/Login.vue')
}
]
const router = new VueRouter({
routes
})
router.beforeEach(async(to,from,next)=>{
console.log('********全局守卫**********');
if(to.path=="/login"){
next()
}else{
let token=localStorage.getItem('token')
if(!token){
Vue.prototype.$message.error('您还没有登录,请先登录')
router.replace('/login')
}else{
let result=await Vue.prototype.$api.users.getUserInfo()
console.log('result',result);
if(result.code){
next()
if(Vue.prototype.$code!=1){
addRoutes(result.data.permissionList)
Vue.prototype.$code=1
}
}
}
}
})
export default router
5、菜单折叠
-
在Home.vue文件中定义数据isCollpase
export default {
data(){
return{
isCollapse:false,
}
}
}
-
在
<el-header>
区域添加折叠和展开按钮,并根据isCollapse的值控制这两个按钮的显示或隐藏
<el-aside>
<i v-if="!isCollapse" class="el-icon-s-fold" style="margin-left:190px"></i>
<i v-else class="el-icon-s-unfold" style="margin-left:40px"></i>
<!--...其余代码省略-->
</el-aside>
-
为展开和折叠按钮添加绑定单击事件
<el-aside>
<i v-if="!isCollapse" class="el-icon-s-fold" @click="toggleCollpase" style="margin-left:190px"></i>
<i v-else class="el-icon-s-unfold" @click="toggleCollpase" style="margin-left:40px"></i>
<!--...其余代码省略-->
</el-aside>
methods: {
toggleCollpase(){
this.isCollapse=!this.isCollapse;
}
}
-
在
<el-menu>
标签中添加collpase属性来控制菜单的折叠或展开
<el-menu :collapse="isCollapse">
-
在
<el-aside>
中动态设置菜单栏的宽度,同时删除掉之前style="width: 200px"
<el-aside :width="isCollapse?'68px':'220px'">
-
取消切换动画
<el-menu :collapse-transition="false">
三、样式穿透
1、组件之间的样式冲突问题
默认情况下,写在.vue组件中的样式会全局生效,因此很容易造成多个组件之间的样式冲突问题
导致组件之间样式冲突的根本原因是
-
单页面应用程序中,所有组件的DOM结构,都是基于唯一的index.html页面进行呈现的。
-
每个组件的样式,都会影响整个index.html页面中的DOM元素。
2、scoped的底层实现原理
解决样式冲突问题的办法是在<style>
标签之间添加一个scoped属性
<style scoped>
</style>
其实scoped的底层原理是使用了css的属性选择器来完成的。
<template>
<h2 data-v-001>班级列表</h2>
</template>
<style>
h2[data-v-001]{
color: red;
}
</style>
3、样式穿透
复制elementui案例中的样式,复制后边框出不来,要想解决样式穿透问题
样式穿透只存在于局部样式中,即<style>
中添加了scoped属性
-
>>>
或/deep/
:作用于CSS -
::v-deep
:作用于SASS
<style lang="scss" scoped>
.avatar-uploader ::v-deep .el-upload {
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
}
.avatar-uploader ::v-deep .el-upload:hover {
border-color: #409eff;
}
.avatar-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 178px;
height: 178px;
line-height: 178px;
text-align: center;
}
.avatar {
width: 178px;
height: 178px;
display: block;
}
</style>v