登录/退出功能
1 登录概述
1.1 登录业务流程
- 在登录页面输入应户名和密码
- 调用后台接口进行验证
- 通过验证之后 根据后台响应状态跳转到项目主页
1.2 登录业务的相关技术点
- http是无状态的
- 通过cookie在客户端记录状态
- 通过session在服务端记录状态
- 通过token维持状态
如果服务器与客户端之间不存在跨域问题 推荐使用cookie与session
如果服务器与客户端之间存在跨域问题 推荐使用token
2 登录-token原理分析
3 登录功能实现
1 登陆页面布局
通过Element-UI组件来实现布局
- el-form
- el-form-item
- el-input
- el-button
- 字体图标
2 梳理项目结构
- 首先在项目根路径打开终端 检查工作目录是否干净
git status
2. 创建login分支
git checkout -b login
查看当前项目所有分支
3. 清理项目
- 删除App.vue文件中除骨架外的内容
- 删除router文件下index.js中的路由规则
- 删除views文件夹下的组件文件
- 删除components文件夹下的组件文件
- 创建登陆组件
- 在components文件夹下创建登陆组件
<template>
<div>登陆组件</div>
</template>
<script>
export default {
name: 'Login'
}
</script>
<style lang="less" scoped>
</style>
- 在路由中引入Login组件并设置相应的路由规则
import Vue from 'vue'
import VueRouter from 'vue-router'
import Login from '../components/Login'
Vue.use(VueRouter)
const routes = [
{ path: '/login', component: Login }
]
const router = new VueRouter({
routes
})
export default router
- 在App根组件中添加路由占位符
<div id="app">
<!-- 路由占位符-->
<router-view></router-view>
</div>
当访问相应路由规则的时候 就会展示Login组件内容了
- 路由重定向
在路由匹配规则中设置重定向
const routes = [
//设置路由重定向
{ path: '/', redirect: '/login' },
{ path: '/login', component: Login }
]
- 设置背景色
<style lang="less" scoped>
.login_container{
background-color: #2b4b6b;
}
</style>
此时,渲染出来的Login组件并不会占满全屏
于是需要在assets文件夹下新建css文件夹下
再在css文件夹下新建一个全局css文件global.css
/*全局样式表*/
html, body, #app {
height: 100%;
margin: 0;
padding: 0;
}
在全局入口文件main.js中导入global.css
// 导入全局样式表
import './assets/css/global.css'
此时回到Login组件 将添加login_container样式类的div添加样式高度为100%让其占满全屏即可
- 绘制中央登录盒子
在登陆组件中添加div盒子 为其添加样式即可
.login_box{
width: 450px;
height: 300px;
background-color: #fff;
border-radius: 3px;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
- 绘制头像
添加logo的div盒子 引入图片 并添加样式
.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%;
transform: translate(-50%, -50%);
background-color: #fff;
img {
width: 100%;
height: 100%;
border-radius: 50%;
background-color: #eeeeee;
}
- 绘制登录表单
在plugins文件夹下的element.js文件中按需引入Form和FormItem
import Vue from 'vue'
import { Button } from 'element-ui'
import { Form } from 'element-ui'
import { FormItem } from 'element-ui'
import { Input } from 'element-ui'
Vue.use(Button)
Vue.use(Form)
Vue.use(FormItem)
Vue.use(Input)
- 在Element-UI官网寻找Form表单粘贴代码至Login组件中
<!-- 登陆表单区域-->
<el-form label-width="0" class="login_form">
<!-- 用户名-->
<el-form-item>
<el-input ></el-input>
</el-form-item>
<!-- 密码-->
<el-form-item>
<el-input ></el-input>
</el-form-item>
<!-- 按钮-->
<el-form-item class="btns">
<el-button type="primary">登录</el-button>
<el-button type="info">重置</el-button>
</el-form-item>
</el-form>
添加相应样式
.login_form {
padding: 0 20px;
width: 100%;
position: absolute;
bottom: 0;
box-sizing: border-box;
}
.btns {
display: flex;
justify-content: flex-end;
}
- 添加字体图标
同理先去Elemen-UI官网寻找字体图标
发现图标不够 于是选用一套第三方图标库–阿里矢量图标库
引入基础icon图标类
// 导入字体图标库
import './assets/fonts/iconfont.css'
添加图标
<el-input prefix-icon="iconfont icon-user"></el-input>
效果如图
- 表单数据绑定
element-ui的表单中可以绑定data属性中的对象
每一个输入框中绑定该对象的属性
//表单绑定
<el-form :model="loginForm" label-width="0" class="login_form">
//输入框绑定
<el-input v-model="loginForm.username" prefix-icon="iconfont icon-user"></el-input>
<el-input v-model="loginForm.password" prefix-icon="iconfont icon-3702mima"></el-input>
//dta中的数据
data() {
return {
loginForm: {
username: '',
password: ''
}
}
}
隐藏密码框的数据 为输入框添加“type=“password””即可
- 数据表单验证
element-ui为表单绑定一个rules验证规则进行数据验证 该验证规则也在data中声明
绑定验证规则
<el-form :rules="loginFormRules" :model="loginForm" label-width="0" class="login_form">
<!-- 用户名-->
<el-form-item prop="username">
<el-input v-model="loginForm.username" prefix-icon="iconfont icon-user"></el-input>
</el-form-item>
<!-- 密码-->
<el-form-item prop="password">
<el-input type="password" v-model="loginForm.password" prefix-icon="iconfont icon-3702mima"></el-input>
</el-form-item>
声明验证规则
data() {
return {
// 表单验证规则
loginFormRules: {
username: [
{ required: true, message: '请输入用户名', trigger: 'blur' },
{ min: 5, max: 10, message: '长度在5到10个字符', trigger: 'blur' }
],
password: [
{ required: true, message: '请输入用户名', trigger: 'blur' },
{ min: 5, max: 10, message: '长度在5到10个字符', trigger: 'blur' }
]
}
}
}
required:表示是否为必填项
message: 表示提示信息
trigger:表示验证时机
min:表示最小长度
max:表示最大长度
- 设置重置按钮
element-ui在form表单中提供了reSetfiled方法 只需拿到表单的引用对象
就能重置表单
方法名 | 说明 |
---|---|
resetFields | 对整个表单进行重置,将所有字段值重置为初始值并移除校验结果 |
<el-form ref="loginFormRef" :rules="loginFormRules" :model="loginForm" label-width="0" class="login_form">
此处的ref就是表单的引用对象
为重置按钮绑定单击事件
<el-button type="info" @click="resetLoginForm">重置</el-button>
在methods中声明单击事件处理函数 调用element-ui为该表单引用对象绑定的resetFields方法
methods: {
// 点击重置按钮 重置表单对象
resetLoginForm() {
this.$refs.loginFormRef.resetFields();
}
}
this.$refs.loginFormRef是表单的实例对象
- 表单的预验证
与表单的重置类似 也是通过表单的引用对象调用element-ui为其绑定的validate方法
方法名 | 说明 | 参数 |
---|---|---|
validate | 对整个表单进行校验的方法,参数为一个回调函数。该回调函数会在校验结束后被调用,并传入两个参数:是否校验成功和未通过校验的字段。若不传入回调函数,则会返回一个 promise | Function(callback: Function(boolean, object)) |
- 通过axios发起登录请求
首先依然是在入口文件中导入axios
// 导入axios
import axios from 'axios'
// 设置默认根路径
axios.defaults.baseURL = 'http://127.0.0.1:8888/api/private/v1/';
// 将axios挂载到vue原型实例上
Vue.prototype.$http = axios;
如果预验证失败 直接return
如果预验证成功 则调用axios方法发起登录请求
配置弹框提示
import { Message } from 'element-ui'
//挂载至全局
Vue.prototype.$message = Message;
// 登录函数
login() {
this.$refs.loginFormRef.validate(async valid => {
// console.log(valid);
if(!valid) return;
const { data: res } = await this.$http.post('login', this.loginForm);
if(res.meta.status !== 200) return this.$message.error('登录失败!');
this.$message.success('登陆成功!');
// 将登录成功后的token值保存在sessionStorage(token只应该在当前网站打开期间生效)中
window.sessionStorage.setItem("token", res.data.token);
// 通过编程式导航跳转到主页
this.$router.push('/home');
})
}
- 设置路由导航守卫来判断 是否登录
// 挂在路由导航守卫
router.beforeEach((to, from, next) => {
// to是将要访问的路径
// from代表从哪个路径而来
// next代表放行
if (to.path === '/login') return next();
// 获取token
const tokenStr = window.sessionStorage.getItem('token');
if (!tokenStr) return next('/login')
next()
});
4 退出
退出实现的原理
基于token退出 只需销毁本地token即可 后续请求就不会携带token 必须重新登录生成token才可以访问页面
logout() {
// 销毁token
window.sessionStorage.clear();
// 跳转到登录页面
this.$router.push('/login')
}