登录表单的校验
**目标**对登录表单进行规则校验
基础模板已经有了基础校验的代码,所以我们这一章节更多的是修正和完善
el-form表单校验的先决条件
手机号和密码的校验
字段名对应
为什么要对应? 因为基础模板采用的是**
username的字段,但是实际接口中采用的是mobile的字段,为了更方便的写代码,所以我们将username改成mobile**
这里除了字段名,还有我们的规则校验名称,以及prop名称。
<el-form :model="loginForm" :rules="loginRules" class="login-form" auto-complete="on" label-position="left" >
<el-form-item prop="mobile">
<el-input
v-model="loginForm.mobile"
placeholder="请输入手机号"
name="username"
type="text"
tabindex="1"
auto-complete="on"
/>
</el-form-item>
<el-form-item prop="password">
<el-input
:key="passwordType"
ref="password"
v-model="loginForm.password"
:type="passwordType"
placeholder="请输入密码"
name="password"
tabindex="2"
auto-complete="on"
@keyup.enter.native="handleLogin"
/>
</el-form-item>
英文提示变成中文
基础模板中都是placeHolder占位符是英文,要变成中文
登录按钮文字同样需要换成中文
校验手机号和校验密码
基础模板中,已经做了校验,我们针对代码进行一些优化
新规则:手机号必填,并且进行格式校验,密码必填,长度6-16位之间
import { validMobile } from '@/utils/validate.js'
data() {
// 自定义校验函数
const validateMobile = function(rule, value, callback) {
// 校验value
// if (validMobile(value)) {
// // 如果通过 直接执行callback
// callback()
// } else {
// callback(new Error('手机号格式不正确'))
// }
validMobile(value) ? callback() : callback(new Error('手机号格式不正确'))
}
return {
loginForm: {
mobile: '13800000002',
password: '123456'
},
loginRules: {
mobile: [{ required: true, trigger: 'blur', message: '手机号不能为空' }, {
validator: validateMobile, trigger: 'blur'
}],
password: [{ required: true, trigger: 'blur', message: '密码不能为空' }, {
min: 6, max: 16, message: '密码的长度在6-16位之间 ', trigger: 'blur'
}]
},
loading: false,
passwordType: 'password',
redirect: undefined
}
},
我们在**utils/validate.js**方法中增加了一个校验手机号的方法
/**
* 校验手机号
* **/
export function validMobile(str) {
return /^1[3-9]\d{9}$/.test(str) // 校验手机号
}
**utils/validate.js**是一个专门存放校验工具方法的文件
关于修饰符
关于修饰符
在该页面中,我们发现了事件的几个修饰符
@keyup.enter.native@click.native.prevent
@keyup.**enter**属于按键修饰符,如果我们想监听在按回车键的时候触发,可以如下编写
<!-- 只有在 `key` 是 `Enter` 时调用 `vm.submit()` -->
<input v-on:keyup.enter="submit">
@keyup.enter.native 表示监听组件的原生事件,比如 keyup就是于input的原生事件,这里写native表示keyup是一个原生事件
提交代码
本节任务:实现登录用户的手机号和密码校验
Vue-Cli配置跨域代理
目标: 通过配置vue-cli的代理解决跨域访问的问题
为什么会出现跨域?
当下,最流行的就是**前后分离项目,也就是前端项目和后端接口并不在一个域名之下,那么前端项目访问后端接口必然存在跨域**的行为.
怎么解决这种跨域 ?
请注意,我们所遇到的这种跨域是位于开发环境的,真正部署上线时的跨域是生产环境的
解决开发环境的跨域问题
开发环境的跨域
开发环境的跨域,也就是在**vue-cli脚手架环境下开发启动服务时,我们访问接口所遇到的跨域问题,vue-cli为我们在本地开启了一个服务,可以通过这个服务帮我们代理请求**,解决跨域问题
这就是vue-cli配置webpack的反向代理
采用vue-cli的代理配置
vue-cli的配置文件即**vue.config.js**,这里有我们需要的 代理选项
module.exports = {
devServer: {
// 省略前面的代码
// 代理配置
proxy: {
// 这里的api 表示如果我们的请求地址有/api的时候,就出触发代理机制
// localhost:8888/api/abc => 代理给另一个服务器
// 本地的前端 =》 本地的后端 =》 代理我们向另一个服务器发请求 (行得通)
// 本地的前端 =》 另外一个服务器发请求 (跨域 行不通)
'/api': {
target: 'www.baidu.com', // 我们要代理的地址
changeOrigin: true, // 是否跨域 需要设置此值为true 才可以让本地服务代理我们发出请求
// 路径重写
pathRewrite: {
// 重新路由 localhost:8888/api/login => www.baidu.com/api/login
'^/api': '' // 假设我们想把 localhost:8888/api/login 变成www.baidu.com/login 就需要这么做
}
},
}
}
}
以上就是我们在vue-cli项目中配置的代理设置
接下来,我们在代码中将要代理的后端地址变成 后端接口地址
vue.config.js里面devServer
module.exports = {
devServer: {
// 省略前面的代码
// 代理跨域的配置
proxy: {
// 当我们的本地的请求 有/api的时候,就会代理我们的请求地址向另外一个服务器发出请求
'/api': {
target: 'http://ihrm-java.itheima.net/', // 跨域请求的地址
// 另外一个服务器地址:http://ihrm.itheima.net/ 此服务器管理员密码禁止修改
changeOrigin: true // 只有这个值为true的情况下 才表示开启跨域
}
}
}
}
本节注意:我们并没有进行**pathRewrite,因为后端接口就是ihrm-java.itheima.net/api**这种格式,所以不需要重写
vue.config.js的改动如果要生效,需要进行重启服务
同时,还需要注意的是,我们同时需要注释掉 mock的加载,因为mock-server会导致代理服务的异常
// before: require('./mock/mock-server.js'), // 注释mock-server加载
生产环境的跨域
生产环境表示我们已经开发完成项目,将项目部署到了服务器上,这时已经没有了vue-cli脚手架的**辅助了,我们只是把打包好的html+js+css交付运维人员,放到Nginx服务器而已,所以此时需要借助Nginx**的反向代理来进行
server{
# 监听9099端口
listen 9099;
# 本地的域名是localhost
server_name localhost;
#凡是localhost:9099/api这个样子的,都转发到真正的服务端地址http://baidu.com
location ^~ /api {
proxy_pass http://baidu.com;
}
}
注意:这里的操作一般由运维人员完成,需要前端进行操作,这里我们进行一下简单了解
更多正向代理和反向代理知识,请阅读这篇文章Nginx反向代理
提交代码
本节注意:我们并没有进行**pathRewrite,因为后端接口就是ihrm-java.itheima.net/api**这种格式,所以不需要重写
本节任务: 配置vue-cli的反向代理,实现后端接口的跨域访问
封装Vuex的登录Action并处理token
**目标**在vuex中封装登录的action,并处理token
在这个小节中,我们将在vuex中加入对于用户的登录的处理
在Vuex中对token进行管理
在传统模式中,我们登录的逻辑很简单,如图
实现store/modules/user.js基本配置
// 状态
const state = {}
// 修改状态
const mutations = {}
// 执行异步
const actions = {}
export default {
namespaced: true,
state,
mutations,
actions
}
设置token的共享状态
const state = {
token: null
}
我们需要知道,**
钥匙**不能每次都通过登录获取,我们可以将token放置到本地的缓存中
在**utils/auth.js中,基础模板已经为我们提供了获取token,设置token,删除token**的方法,可以直接使用
只需要将存储的key放置成特定值即可
import Cookies from 'js-cookie'
const TokenKey = 'hrsaas-ihrm-token' // 设定一个独一无二的key
export function getToken() {
return Cookies.get(TokenKey)
}
export function setToken(token) {
return Cookies.set(TokenKey, token)
}
export function removeToken() {
return Cookies.remove(TokenKey)
}
初始化token状态 - store/modules/user.js
import { getToken, setToken, removeToken } from '@/utils/auth'
// 状态
// 初始化的时候从缓存中读取状态 并赋值到初始化的状态上
// Vuex的持久化 如何实现 ? Vuex和前端缓存相结合
const state = {
token: getToken() // 设置token初始状态 token持久化 => 放到缓存中
}
提供修改token的mutations
// 修改状态
const mutations = {
// 设置token
setToken(state, token) {
state.token = token // 设置token 只是修改state的数据 123 =》 1234
// vuex变化 => 缓存数据
setToken(token) // vuex和 缓存数据的同步
},
// 删除缓存
removeToken(state) {
state.token = null // 删除vuex的token
removeToken() // 先清除 vuex 再清除缓存 vuex和 缓存数据的同步
}
}
封装登录的Action
封装登录的action
登录action要做的事情,
调用登录接口,成功后设置token到vuex,失败则返回失败
import { login } from '@/api/user'
// 执行异步
const actions = {
// 定义login action 也需要参数 调用action时 传递过来的参数
async login(context, data) {
const result = await login(data) // 实际上就是一个promise result就是执行的结果
// axios默认给数据加了一层data
if (result.data.success) {
// 表示登录接口调用成功 也就是意味着你的用户名和密码是正确的
// 现在有用户token
// actions 修改state 必须通过mutations
context.commit('setToken', result.data.data)
}
}
}
上述代码中,我们使用了**
async/await语法,如果用then**语法也是可以的
// 为什么async/await 不用返回new Promise,因为 async函数本身就是 Promise,promise的值返回的值
login(context, data) {
return new Promise(function(resolve) {
login(data).then(result => {
if (result.data.success) {
context.commit('setToken', result.data.data) // 提交mutations设置token
resolve() // 表示执行成功了
}
})
})
}
以上两种写法都是OK的,我们在项目研发过程中,尽可能的采用前一种
除此之外,为了更好的让其他模块和组件更好的获取token数据,我们可以在**store/getters.js**中将token值作为公共的访问属性放出
const getters = {
sidebar: state => state.app.sidebar,
device: state => state.app.device,
token: state => state.user.token // 在根级的getters上 开发子模块的属性给别人看 给别人用
}
export default getters
提交代码