1. 完成用户登录操作
1.1 用户登录流程
用户登录完成之后 需要将密钥进行保存. Session,Cookie
将页面跳转到系统首页.
1.2 Session和Cookie介绍
1.2.1 Session 会话机制
服务器保存用户信息的一种手段. 可以将用户登录信息通过session的方式进行保存. 当会话关闭时,Session对象销毁.
1
1.2.2 Cookie 机制
Cookie,有时也用其复数形式 Cookies。类型为“小型文本文件”,是某些网站为了辨别用户身份,进行Session跟踪而储存在用户本地终端上的数据(通常经过加密),由用户客户端计算机暂时或永久保存的信息 [1] 。
概括: Cookie是客户端保存服务器信息的一种机制 可以做到永久保存
Cookie的规则:
- 浏览器只能查看当前网址的Cookie的记录. 相对安全
- Cookie可以设置共享 ,但是需要指定 xxx.com 域名
- Cookie可以设定失效时间 单位为秒
1.3 前端用户登录操作
<!-- 定义模版对象 -->
<template>
<div class="login_container">
<div class="login_box">
<!-- 头像区域-->
<div class="avatar_box">
<img src="../assets/logo.png" alt="VUE图片" />
</div>
<!-- ref: form表单可以通过ref进行引用
:model: 对整个表单进行数据的绑定
:rules 对整个表单数据进行数据校验
-->
<el-form ref="loginFormRef" label-width="0" :rules="rules" class="login_form" :model="loginForm"
@submit.native.prevent>
<el-form-item prop="username">
<el-input prefix-icon="iconfont iconuser" v-model="loginForm.username"></el-input>
</el-form-item>
<el-form-item prop="password">
<el-input prefix-icon="iconfont iconsuo" type="password" v-model="loginForm.password"></el-input>
</el-form-item>
<el-form-item class="btns">
<el-button type="primary" @click="login" native-type="submit">登录</el-button>
<el-button type="info" @click="reset">重置</el-button>
</el-form-item>
</el-form>
</div>
</div>
</template>
<!-- 定义JS变量 -->
<script>
export default {
data(){
return {
loginForm: {
username: '',
password: ''
},
rules: {
username: [
/* required 是否为必填项 message:提示信息 trigger:出发条件 */
{ required: true, message: '请输入用户名', trigger: 'blur' },
{ min: 3, max: 30, message: '长度在 3 到 30 个字符', trigger: 'blur' }
],
password: [
/* required 是否为必填项 message:提示信息 trigger:出发条件 */
{ required: true, message: '请输入密码', trigger: 'blur' },
{ min: 3, max: 30, message: '长度在 3 到 30 个字符', trigger: 'blur' }
]
}
}
},
methods: {
reset(){
//将表单数据改为空串
/* this.loginForm.username = ''
this.loginForm.password = '' */
/* this:代表当前的Vue的组件对象 */
/* $refs
1.$从vue对象中获取数据
2.从vue组件对象中获取全部ref标签 */
this.$refs.loginFormRef.resetFields()
},
login(){
//1.获取表单数据
this.$refs.loginFormRef.validate(async valid => {
//2.当程序没有通过校验时 程序终止
if(!valid) return
//3.发起ajax请求, 实现业务调用
//参数1: url地址 参数2:传递的数据
let {data: result} =
await this.$http.post("/user/login",this.loginForm)
//4.判断用户校验是否正常 status=200 201
if(result.status !== 200) return this.$message.error("用户名或密码错误")
this.$message.success("恭喜你 登录成功!")
//如何获取token result.data
//将用户信息保存到session中
window.sessionStorage.setItem("token",result.data)
//window.sessionStorage.removeItem("token") 删除单个
//window.sessionStorage.clear() //全部删除
//5.登录成功之后,跳转到/home页面中
this.$router.push("/home")
})
}
}
}
</script>
<!-- 防止组件冲突 -->
<style lang="less" scoped>
.login_container{
background-color: #2b4b6b;
height: 100%;
}
.login_box {
width: 450px;
height: 300px;
background-color: #FFFFFF;
/* 设定圆弧角*/
border-radius: 10px;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
.avatar_box {
height: 130px;
width: 130px;
border: 1px solid #EEEEEE;
border-radius: 50%;
padding: 10px;
box-shadow: 0 0 10px #DDDDDD; /* 添加阴影*/
position: absolute; /* 绝对定位*/
left: 50%; /* 距离左侧50%*/
transform: translate(-50%,-50%); /*回调50%*/
background-color: #FFFFFF;
img {
height: 100%;
width: 100%;
border-radius: 50%;
background-color: #EEEEEE;
}
}
.btns {
display: flex;
justify-content: flex-end;
}
.login_form {
position: absolute;
bottom: 0;
width: 100%;
padding: 0 20px;
box-sizing: border-box;
}
}
</style>
2 后台首页实现
2.1 后台首页跳转
2.1.1 配置路由规则
说明: 要求用户通过/home请求,跳转到Home.vue的页面中. 编辑router/index.js 文件
2.2.3 编辑路由导航守卫
//定义路由导航守卫 考点: 拦截器
/**
* 1.遍历的每个路由都会执行回调函数.
* 2.参数信息: 3个
* 2.1 to: 请求访问的地址 到哪去
* 2.2 from: 请求从哪里跳转而来 从哪来
* 2.3 next: 是一个函数 next() 请求放行
* next("/login") 发起login请求
*/
router.beforeEach((to,from,next) => {
//1.如果用户访问/login的请求,应该直接放行
if(to.path === '/login') return next()
//2.不是访问的登录页面,所以判断用户是否登录. 判断依据token
let token = window.sessionStorage.getItem("token")
//3.如果!token 没有值,则执行if之后的操作
if(!token) return next("/login")
//4.如果代码执行到这一行,说明用户已经登录.则放行
next()
})
3.3标题容器布局代码
<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>
3.6实关于表设计自关联说明
问题: 如何设计表,实现3级菜单表?
思考: 表关联的层级不要太多, 左链接的查询会写的异常困难. 如何提高软件的扩展性. 自关联
表设计: 设定一张表 通过ID,和parentID 定义表的父子关系.
3.7项目中的布局结构
3.8 左侧菜单实现
3.8.1 左侧菜单说明
<el-menu
default-active="2" class="el-menu-vertical-demo"
@open="handleOpen" @close="handleClose"
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-1">懂1</el-menu-item>
<el-menu-item index="1-2">懂2</el-menu-item>
</el-submenu>
</el-menu>
后端项目左侧菜单实现
<template>
<!-- 定义布局容器 -->
<el-container class="home-container">
<!-- 定义头标签 -->
<el-header>
<div>
<img src="../assets/images/logo.png" />
<span>京淘电商后台管理系统</span>
</div>
<el-button type="info" @click="logout">退出</el-button>
</el-header>
<!-- 定义中间区域-->
<el-container>
<!-- 当打开左侧菜单时 宽度为200, 当不打开时为默认值-->
<el-aside :width="isCollapse ? '64px' : '200px' ">
<!-- 这是左侧菜单-->
<!--定义折叠项-->
<div class="leftCollapse" @click="collspseClick">|||</div>
<!--
background-color 定义背景色
text-color="#fff" 定义文字颜色
active-text-color="#4094ff" 选中元素的颜色
unique-opened 是否只保持一个子菜单的展开
collapse 是否水平折叠收起菜单(仅在 mode 为 vertical 时可用)
collapse-transition 是否开启折叠动画 默认不要展现
router 是否使用 vue-router 的模式,启用该模式会在激活导航时以 index 作为 path 进行路由跳转
-->
<el-menu background-color="#2C3E50" text-color="#fff"
active-text-color="#4094ff" unique-opened
:collapse="isCollapse" :collapse-transition="isCollapseTransition"
router :default-active="defaultActive">
<!-- 定义一级菜单 -->
<el-submenu :index="menu.id+''" v-for="menu in menuList" :key="menu.id">
<!-- 定义一级菜单模版 -->
<template slot="title">
<!-- 定义左侧图标-->
<i :class="menuIcon[menu.id]"></i>
<!-- 定义菜单名称-->
<span>{{menu.name}}</span>
</template>
<!-- 定义二级菜单 -->
<el-menu-item :index="childrenMenu.path" v-for="childrenMenu in menu.children" :key="childrenMenu.id"
@click="defaultActiveMenu(childrenMenu.path)">
<template slot="title">
<i class="el-icon-menu"></i>
<span>{{childrenMenu.name}}</span>
</template>
</el-menu-item>
</el-submenu>
</el-menu>
</el-aside>
<!-- 定义主页面结构-->
<el-main>
<!-- 定义路由展现页面-->
<router-view></router-view>
</el-main>
</el-container>
</el-container>
</template>
<script>
export default {
//初始化函数
created() {
//动态获取左侧菜单信息
this.getMenuList()
//设定模式选中按钮
this.defaultActive = window.sessionStorage.getItem("activeMenu")
},
data() {
return {
//左侧菜单数据
menuList: [],
menuIcon: {
'1': 'iconfont iconuser',
'3': 'iconfont iconshangpin',
'5': 'iconfont iconicon--copy',
'7': 'iconfont iconquanxian',
'8': 'iconfont iconziyuan'
},
//定义是否折叠
isCollapse: false,
//是否展现折叠动态效果
isCollapseTransition: false,
//定义默认高亮
defaultActive: ''
}
},
methods: {
logout() {
//1.删除token数据
window.sessionStorage.clear()
//2.跳转到用户登录页面 注意路径的写法 加/
this.$router.push("/login")
},
async getMenuList() {
const {data: result} = await this.$http.get('/rights/getRightsList')
if(result.status !== 200) return this.$message.error("左侧菜单查询失败")
//如果请求正常,则将返回值结果赋值给vue的data
this.menuList = result.data
},
//设定左侧折叠展开效果
collspseClick() {
this.isCollapse = !this.isCollapse
},
defaultActiveMenu(activeMenu){
//为了实现返回之后的选中效果,应该将数据保存到第三方中sessionStory
window.sessionStorage.setItem("activeMenu",activeMenu)
this.defaultActive = activeMenu
}
}
}
</script>
<!-- 防止样式重叠 -->
<style lang="less" scoped>
.el-header {
background-color: #2B4B6B;
display: flex; //灵活的盒子容器
justify-content: space-between; //左右对齐
align-items: center; //文本元素居中对齐
color: #FFFFFF; //设定字体颜色
padding-left: 1px;
>div {
display: flex;
align-items: center;
span {
margin-left: 15px;
font-size: 25px; //设定字体高度
}
}
}
.el-aside {
background-color: #2C3E50;
.el-menu {
border-right: none;
}
}
.el-main {
background-color: #EEEEEE;
}
.home-container {
height: 100%;
width: 100%;
}
.iconfont {
margin-right: 8px;
}
//定义折叠项
.leftCollapse {
//设定背景色
background-color: #708090;
//定义字体大小
font-size: 10px;
//定义行高
line-height: 30px;
//定义颜色
color: #FFFFFF;
//设置居中
text-align: center;
//设定字符间距
letter-spacing: 4px;
//鼠标放上之后设置为小手
cursor: pointer;
}
</style>
3.9.2 定义路由标签
在home的main中添加路由占位符.