学习源码可以看我的个人前端学习笔记 (github.com):qdxzw/humanResourceIntelligentManagementProject
觉得有帮助的同学,可以点心心支持一下哈
登录页的结构和表单
准备登录页面的样式和结构
拷贝登录页的基本结构布局-代码位置(src/views/login/index.vue)
<template>
<div class="login-container">
<div class="logo" />
<div class="form">
<h1>登录</h1>
<el-card shadow="never" class="login-card">
<!--登录表单-->
</el-card>
</div>
</div>
</template>
<script>
export default {
name : "Login"
}
</script>
<style lang="scss">
.login-container {
display: flex;
align-items: stretch;
height: 100vh;
.logo {
flex: 3;
background: rgba(38, 72, 176) url(../../assets/common/login_back.png)
no-repeat center / cover;
border-top-right-radius: 60px;
display: flex;
flex-direction: column;
align-items: flex-end;
justify-content: center;
padding: 0 100px;
.icon {
background: url(../../assets/common/logo.png) no-repeat 70px center /
contain;
width: 300px;
height: 50px;
margin-bottom: 50px;
}
p {
color: #fff;
font-size: 18px;
margin-top: 20px;
width: 300px;
text-align: center;
}
}
.form {
flex: 2;
display: flex;
flex-direction: column;
justify-content: center;
padding-left: 176px;
.el-card {
border: none;
padding: 0;
}
h1 {
padding-left: 20px;
font-size: 24px;
}
.el-input {
width: 350px;
height: 44px;
.el-input__inner {
background: #f4f5fb;
}
}
.el-checkbox {
color:#606266;
}
}
}
</style>
实现登录表单的结构
<el-form>
<el-form-item>
<el-input placeholder="请输入手机号" />
</el-form-item>
<el-form-item>
<el-input type="password" placeholder="请输入密码" />
</el-form-item>
<el-form-item>
<el-checkbox> 用户平台使用协议 </el-checkbox>
</el-form-item>
<el-form-item>
<el-button style="width: 350px" type="primary">登录</el-button>
</el-form-item>
</el-form>
实现登录表单校验
ref、:model、:rules、prop
<el-form
ref="form"
autocomplete="off"
:model="loginForm"
:rules="loginRules"
>
<el-form-item prop="mobile">
<el-input v-model="loginForm.mobile" placeholder="请输入手机号" />
</el-form-item>
<el-form-item prop="password">
<el-input
v-model="loginForm.password"
type="password"
placeholder="请输入密码"
/>
</el-form-item>
<el-form-item prop="isAgree">
<el-checkbox v-model="loginForm.isAgree">
用户平台使用协议
</el-checkbox>
</el-form-item>
<el-form-item>
<el-button style="width: 350px" type="primary" @click="login"
>登录</el-button
>
</el-form-item>
</el-form>
手机号 必填,手机号规则;密码 必填,6-16位长度;用户协议 必须勾选
loginForm: {
mobile: '',
password: '',
isAgree: false
},
loginRules: {
mobile: [
{
required: true,
message: '请输入手机号',
trigger: 'blur'
},
{
pattern:
/^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$/,
message: '手机号格式不正确',
trigger: 'blur'
}
],
password: [
{
required: true,
message: '请输入密码',
trigger: 'blur'
},
{
min: 6,
max: 16,
message: '密码长度应该为6-12之间',
trigger: 'blur'
}
],
// required只能检测null undefined ""
isAgree: [
{
validator: (rule, value, callback) => {
// rule校验规则
// value检验的值
// callback函数-promise reslove reject
// callback() callback(new Error(错误信息))
value ? callback() : callback(new Error('您必须勾选协议'))
}
}
]
}
表单整体校验
login () {
this.$refs.form.validate(isOk => {
if (isOk) {
alert('校验通过')
}
})
}
分析登录流程
Vuex用户模块
在src/store/modules/user.js中管理token
实现token的Vuex数据持久化
实现登录的action方法
import { getToken, setToken, removeToken } from '@/utils/auth'
const state = {
token: getToken() // 从缓存中读取初始值
}
const mutations = {
setToken (state, token) {
state.token = token
// 同步到缓存
setToken(token)
},
removeToken (state) {
// 删除Vuex的token
state.token = null
removeToken()
}
}
const actions = {
// context上下文,传入参数
login (context, data) {
console.log(data)
// 调用登录接口
// 放回一个token 123456
context.commit('setToken', '123456')
}
}
export default {
namespaced: true, // 开启命名空间
state,
mutations,
actions
}
调用VuexAction
login () {
this.$refs.form.validate(isOk => {
if (isOk) {
this.$store.dispatch('user/login', this.loginForm)
}
})
}
vue-cli代理解决跨域
原理:代理服务器和浏览器是同源的,服务器与服务器之间不存在同源策略,所以代理服务器可以和后端服务器进行请求
vue.config.js(改完要重启),注意删除原有的before配置选项
proxy: {
// path: 目标服务器 百度 新浪 网易 ...
'/api': {
target: 'https://heimahr.itheima.net/' // 要代理的目标地址
}
}
// before: require('./mock/mock-server.js') 基础模板做的模拟数据 拦截请求
发请求验证
<el-button @click="testAjax">测试接口</el-button>
import axios from 'axios'
testAjax () {
axios({
// url: 'https://heimahr.itheima.net/api/sys/login',
url: '/api/sys/login', // http://localhost:9528/api/sys/login =>https://heimahr.itheima.net/api/sys/login
method: 'post',
data: {
mobile: '13800000002',
password: 'hm#qd@23!'
}
})
}
成功截图
axios封装
axios封装的需求
axios功能
基础配置(基地址,超时);请求拦截器,响应拦截器
import axios from 'axios'
import store from '@/store'
import { Message } from 'element-ui'
// 创建一个新的axios实例
const service = axios.create({
baseURL: '/api', // 基地址
timeout: 10000 // 超时时间
})
// 请求拦截器,成功执行第一个,失败执行第二个
service.interceptors.request.use(
config => {
// 注入token
// store.getters.token=>请求头里面
if (store.getters.token) {
config.headers.Authorization = `Bearer ${store.getters.token}`
}
return config
},
error => {
// 失败执行promise
return Promise.reject(error)
}
)
// 响应拦截器
service.interceptors.response.use(
response => {
// axios默认包裹了data
const { data, message, success } = response.data
if (success) {
return data
} else {
Message({
type: 'error',
message: message
})
return Promise.reject(new Error(message))
}
},
error => {
Message({
type: 'error',
message: error.message
})
return Promise.reject(error)
}
)
export default service
发请求验证
<el-button @click="testAxios">测试axios封装</el-button>
import request from '@/utils/request'
testAxios () {
request({
url: '/sys/login',
method: 'post',
data: {
mobile: '13800000002',
password: 'hm#qd@23!'
}
})
}
环境区分
axios的请求处理基地址
开发环境配置变量
# just a flag
ENV = 'development'
# base api
VUE_APP_BASE_API = '/api'
import axios from 'axios'
import store from '@/store'
import { Message } from 'element-ui'
// 创建一个新的axios实例
const service = axios.create({
baseURL: process.env.VUE_APP_BASE_API, // 基地址
timeout: 10000 // 超时时间
})
登录联调
1.封装API请求
import request from '@/utils/request'
export function login (data) {
return request({
url: '/sys/login',
method: 'post',
data // body参数位于data
})
}
2.Vuex调用
const actions = {
// context上下文,传入参数
async login (context, data) {
// console.log(data)
// 调用登录接口
const token = await login(data)
// 放回一个token 123456
context.commit('setToken', token)
}
}
3.跳转主页
async login () {
this.$refs.form.validate(async isOk => {
if (isOk) {
await this.$store.dispatch('user/login', this.loginForm)
// Vuex中的action返回的是promise
// 跳转主页
this.$router.push('/')
}
})
}
4.区分环境数据
loginForm: {
mobile: process.env.NODE_ENV === 'development' ? '13800000002' : '',
password: process.env.NODE_ENV === 'development' ? 'hm#qd@23!' : '',
isAgree: process.env.NODE_ENV === 'development'
}