目录
01: 构建登录模块基础UI结构
02: 表单校验实现原理与方案分析
表单校验的实现原理
自定义表单校验方案分析
文章中的方案实现
03: 基于 vee-validate 实现普适的表单校验
04: 什么是人类行为验证?它的目的、实现原理、构建方案分别是什么?
什么是人类行为验证
目的
它的实现原理是什么?
我们如何在项目中使用它
05: 构建人类行为验证模块
06: 用户登录行为处理
07: 用户信息获取行为
08: 退出登录操作
09: token 超时处理
10: 注册页面基本样式处理
11: 处理注册行为
12: 总结
01: 构建登录模块基础UI结构
- src/views
- - login-register
- - - components
- - - - header.vue
- - - login
- - - - index.vue
// src/views/login-register/components/header.vue
<template>
<!-- 头部图标:PC端 -->
<div class="hidden pt-5 h-8 xl:block">
<img
v-lazy
class="m-auto"
src="https://res.lgdsunday.club/signlogo.png"
alt=""
/>
</div>
<!-- 头部图标:移动端 -->
<div class="h-[111px] xl:hidden">
<img
v-lazy
class="dark:hidden"
src="https://res.lgdsunday.club/login-bg.png"
alt=""
/>
<img
v-lazy
class="h-5 absolute top-[5%] left-[50%] translate-x-[-50%]"
src="https://m.imooc.com/static/wap/static/common/img/logo-small@2x.png"
alt=""
srcset=""
/>
</div>
</template>
// src/views/login-register/login/index.vue
<template>
<div
class="relative h-screen bg-white dark:bg-zinc-800 text-center xl:bg-zinc-200"
>
<!-- 头部图标:PC端 -->
<header-vue></header-vue>
<!-- 表单区 -->
<div
class="block px-3 mt-4 dark:bg-zinc-800 xl:bg-white xl:w-[388px] xl:dark:bg-zinc-900 xl:m-auto xl:mt-8 xl:py-4 xl:rounded-sm xl:shadow-lg"
>
<h3
class="mb-2 font-semibold text-base text-main dark:text-zinc-300 hidden xl:block"
>
账号登录
</h3>
<!-- 表单 -->
<vee-form @submit="onLoginHandler">
<vee-field
class="dark:bg-zinc-800 dark:text-zinc-400 border-b-zinc-400 border-b-[1px] w-full outline-0 pb-1 px-1 text-base focus:border-b-main dark:focus:border-b-zinc-200 xl:dark:bg-zinc-900"
name="username"
:rules="validateUsername"
type="text"
placeholder="用户名"
autocomplete="on"
v-model="loginForm.username"
/>
<vee-error-message
class="text-sm text-red-600 block mt-0.5 text-left"
name="username"
>
</vee-error-message>
<vee-field
class="dark:bg-zinc-800 dark:text-zinc-400 border-b-zinc-400 border-b-[1px] w-full outline-0 pb-1 px-1 text-base focus:border-b-main dark:focus:border-b-zinc-200 xl:dark:bg-zinc-900"
name="password"
:rules="validatePassword"
type="password"
placeholder="密码"
autocomplete="on"
v-model="loginForm.password"
/>
<vee-error-message
class="text-sm text-red-600 block mt-0.5 text-left"
name="password"
>
</vee-error-message>
<div class="pt-1 pb-3 leading-[0px] text-right">
<a
class="inline-block p-1 text-zinc-400 text-right dark:text-zinc-600 hover:text-zinc-600 dark:hover:text-zinc-400 text-sm duration-400 cursor-pointer"
@click="onToRegister"
>
去注册
</a>
</div>
<m-button
class="w-full dark:bg-zinc-900 xl:dark:bg-zinc-800"
:loading="loading"
:isActiveAnim="false"
>
登录
</m-button>
</vee-form>
<div class="flex justify-around mt-4">
<!-- QQ -->
<qq-login-vue></qq-login-vue>
<!-- 微信 -->
<wx-login-vue></wx-login-vue>
</div>
</div>
<!-- 人类行为验证模块 -->
<slider-captcha-vue
v-if="isSliderCaptchaVisible"
@close="isSliderCaptchaVisible = false"
@success="onCaptchaSuccess"
></slider-captcha-vue>
</div>
</template>
<script>
export default {
name: 'login'
}
</script>
<script setup>
import headerVue from '../components/header.vue'
import sliderCaptchaVue from './slider-captcha.vue'
import {
Form as VeeForm,
Field as VeeField,
ErrorMessage as VeeErrorMessage
} from 'vee-validate'
import { validateUsername, validatePassword } from '../validate'
import { ref } from 'vue'
import { useStore } from 'vuex'
import { useRouter } from 'vue-router'
import { LOGIN_TYPE_USERNAME } from '@/constants'
import qqLoginVue from './qq-login.vue'
import wxLoginVue from './weixin-login.vue'
const store = useStore()
const router = useRouter()
// 控制 sliderCaptcha 展示
const isSliderCaptchaVisible = ref(false)
/**
* 登录触发
*/
const onLoginHandler = () => {
isSliderCaptchaVisible.value = true
}
/**
* 人类行为验证通过
*/
const onCaptchaSuccess = async () => {
isSliderCaptchaVisible.value = false
// 登录操作
onLogin()
}
// 登录时的 loading
const loading = ref(false)
// 用户输入的用户名和密码
const loginForm = ref({
username: '',
password: ''
})
/**
* 用户登录行为
*/
const onLogin = async () => {
loading.value = true
// 执行登录操作
try {
await store.dispatch('user/login', {
...loginForm.value,
loginType: LOGIN_TYPE_USERNAME
})
} finally {
loading.value = false
}
router.push('/')
}
/**
* 进入注册页面
*/
const onToRegister = () => {
// 配置跳转方式
store.commit('app/changeRouterType', 'push')
router.push('/register')
}
</script>
<style lang="scss" scoped></style>
02: 表单校验实现原理与方案分析
在绝大多数的情况下,我们进行登录时,都会通过 UI 组件库 实现表单校验功能。但是在没有 UI 组件库 的情况下,我们应该如何进行表单校验呢?
想要搞明白这一点,我们首先就需要搞明白表单校验的 实现原理。
表单校验的实现原理
我们知道,所谓表单校验,指的是:
1. 在某一个时机下(失去焦点、内容变化)
2. 检查表单元素中的 value 是否符合某个条件(校验条件)
3. 如果不符合,则给出对应的提示
根据以上描述,我们所需要关注的,其实就是三点内容:
1. 监听表单元素的对应时机
2. 检查内容是否匹配校验条件
3. 根据检查结果,展示对应提示
自定义表单校验方案分析
根据以上原理描述,如果我们想要自定义一套表单校验的功能逻辑,是不是就比较简单了:
1. 创建对应的 field 输入框组件
2. 该组件中,包含两个元素:
1. input 输入框
2. span 表示错误提示
3. 监听 input 输入框的 blur 失去焦点 事件
4. 根据 input 的 value 判断是否满足一个或多个指定的条件(比如:是否为空)
5. 如果不满足,则展示 span 标签,表示错误提示消息
文章中的方案实现
根据以上描述,我们确实可以实现一个基础的表单校验。但是这样的表单校验组件,很难具有 普适 性,因为实际开发中,表单校验的场景多种多样。比如:国际化处理。
把它抽离成一个 通用组件 意义并不大。咱们在文章中,就不会专门去实现这样的一个组件。而是会采用一种更加普适的方式。
这种方式就是:vee-validate
vee-validate 是一个 vue 中专门做表单校验的库,该库更加具有 普适 性,也更加适合大家在实际开发中的使用。
03: 基于 vee-validate 实现普适的表单校验
- src/views/login-register
- - validate.js
// 关键代码
import {
Form as VeeForm,
Field as VeeField,
ErrorMessage as VeeErrorMessage
} from 'vee-validate'
// 三个组件的使用
// src/views/login-register/validate.js
/**
* 用户名的表单校验
*/
export const validateUsername = (value) => {
if (!value) {
return '用户名为必填的'
}
if (value.length < 3 || value.length > 12) {
return '用户名应该在 3-12 位之间'
}
return true
}
/**
* 密码的表单校验
*/
export const validatePassword = (value) => {
if (!value) {
return '密码为必填的'
}
if (value.length < 6 || value.length > 12) {
return '密码应该在 6-12 位之间'
}
return true
}
/**
* 确认密码的表单校验
*/
export const validateConfirmPassword = (value, password) => {
if (value !== password[0]) {
return '两次密码输入必须一致'
}
return true
}
04: 什么是人类行为验证?它的目的、实现原理、构建方案分别是什么?
当表单校验完成之后,接下来我们就来处理 人类行为验证 模块。
想要搞清楚 人类行为验证,就需要搞明白三点内容:
1. 什么是人类行为验证。
2. 它的目的是什么。
3. 它的实现原理是什么。
4. 我们应该如何在项目中使用它。
什么是人类行为验证
在我们日常使用的应用中,人类行为验证其实已经无处不在了。
比如大家应该都见过如下场景:
以上场景,均属于人类行为验证模块。
目的
为什么需要有这样的一个东西呢?这样的一个东西对用户而言是非常讨厌的一个操作。
想要搞明白这个问题,大家就需要先搞清楚现在的应用面临的一个问题。
假如在一个博客系统中,它会根据博客的访问量进行首页排名。假设有一个人,写了一段脚本代码,构建出巨量的 IP 来不断地访问一个指定的博客。这个博客就会被顶到非常靠前的访问位置中。
又假如:在某些投票或者砍价的应用中,也有人利用一段脚本代码,伪造出巨量的用户去进行投票或者砍价的行为,这样的投票或者砍价是不是也就失去了原本的意义。
针对以上这种场景,我们应该如何防止呢?如何能够判断出,当前进行“投票”的操作是 人 进行的,而不是 机器 进行的呢?
想要解决这个问题,就需要使用到 人类行为验证 了。
简单来说,人类行为验证的目的就是:明确当前的操作是人完成的,而非机器。
它的实现原理是什么?
想要完成这样的判断,并且让判断准确,其实是非常复杂的:
人机验证通过对用户的行为数据、设备特征与网络数据构建多维度数据分析,采用完整的可信前端安全方案,保证数据采集的真实性、有效性。 比如以下几个方面(包括但不仅限于):
1. 浏览器特征检查:所有浏览器都有差异,可以通过各种前端相关手段检查浏览器环境的真实性。
2. 鼠标事件(click、move、hover、leave)。
3. 页面窗口(size、scroll、坐标)。
4. cookie。
通过收集到的多维度数据,分析并建立人类行为模型,以此来判断用户是否是一个机器人。
以这样的滚动为例:
人进行的拖动拼图和机器进行的拖动拼图,两者的 鼠标行为轨迹 是不同的。这个不同就是区分人和机器的关键。
我们如何在项目中使用它
目前人类行为验证的实现方案,主要分为两种:
1. 收费平台,年费在几万到几十万不等,有专门的技术人员帮助对接:
极验
网易易盾
2. 免费开源,验证的精准度需要看服务端的能力:
gitee 开源的 SliderCaptcha
我们这里主要是使用这个开源的 SliderCaptcha 实现。
大家在实际项目中可以根据实际情况进行处理。
05: 构建人类行为验证模块
- src/views/login-register/login
- - slider-captcha.vue
// src/views/login-register/login/slider-captcha.vue
<template>
<div
class="fixed top-[20%] left-[50%] translate-x-[-50%] w-[340px] h-[270px] text-sm bg-white dark:bg-zinc-800 rounded border border-zinc-200 dark:border-zinc-900 shadow-3xl"
>
<div class="flex items-center h-5 text-left px-1 mb-1">
<span class="flex-grow dark:text-zinc-200">请完成安全验证</span>
<m-svg-icon
name="refresh"
fillClass="fill-zinc-900 dark:fill-zinc-200"
class="w-3 h-3 p-0.5 rounded-sm duration-300 cursor-pointer hover:bg-zinc-200 dark:hover:bg-zinc-900"
@click="onReset"
></m-svg-icon>
<m-svg-icon
name="close"
fillClass="fill-zinc-900 dark:fill-zinc-200"
class="ml-2 w-3 h-3 p-0.5 rounded-sm duration-300 cursor-pointer hover:bg-zinc-200 dark:hover:bg-zinc-900"
@click="onClose"
></m-svg-icon>
</div>
<div id="captcha"></div>
</div>
</template>
<script>
const EMITS_CLOSE = 'close'
const EMITS_SUCCESS = 'success'
</script>
<script setup>
import '@/vendor/SliderCaptcha/slidercaptcha.min.css'
import '@/vendor/SliderCaptcha/longbow.slidercaptcha.min.js'
import { getCaptcha } from '@/api/sys'
import { onMounted } from 'vue'
const emits = defineEmits([EMITS_CLOSE, EMITS_SUCCESS])
let captcha = null
onMounted(() => {
captcha = sliderCaptcha({
// 渲染位置
id: 'captcha',
// 用户拼图成功之后的回调
async onSuccess(arr) {
const res = await getCaptcha({
behavior: arr
})
if (res) {
emits(EMITS_SUCCESS)
}
},
// 用户拼图失败之后的回调
onFail() {
console.log('onFail')
},
// 默认的验证方法,咱们不在此处进行验证,而是选择在用户拼图成功之后进行验证,所以此处永远返回为 true
verify() {
return true
}
})
})
/**
* 重置
*/
const onReset = () => {
captcha.reset()
}
/**
* 关闭
*/
const onClose = () => {
emits(EMITS_CLOSE)
}
</script>
// index.html
<!-- iconfont 在线图标,主要用于 sliderCaptcha -->
<link rel="stylesheet"
href="https://at.alicdn.com/t/font_3042963_nv614canpao.css?spm=a313x.7781069.1998910419.47&file=font_3042963_nv614canpao.css" />
使用:
// src/views/login-register/login/index.vue
<template>
<!-- 人类行为验证模块 -->
<slider-captcha-vue
v-if="isSliderCaptchaVisible"
@close="isSliderCaptchaVisible = false"
@success="onCaptchaSuccess"
></slider-captcha-vue>
</template>
<script setup>
import sliderCaptchaVue from './slider-captcha.vue'
// 控制 sliderCaptcha 展示
const isSliderCaptchaVisible = ref(false)
/**
* 登录触发
*/
const onLoginHandler = () => {
isSliderCaptchaVisible.value = true
}
/**
* 人类行为验证通过
*/
const onCaptchaSuccess = async () => {
isSliderCaptchaVisible.value = false
// 登录操作
onLogin()
}
</script>
06: 用户登录行为处理
// src/views/login-register/login/index.vue
const store = useStore()
const router = useRouter()
// 登录时的 loading
const loading = ref(false)
// 用户输入的用户名和密码
const loginForm = ref({
username: '',
password: ''
})
/**
* 用户登录行为
*/
const onLogin = async () => {
loading.value = true
// 执行登录操作
try {
await store.dispatch('user/login', {
...loginForm.value,
loginType: LOGIN_TYPE_USERNAME
})
} finally {
loading.value = false
}
router.push('/')
}
我们希望把所有登录逻辑都放入 vuex 中。这是一种比较常见的封装方式。token 的处理、用户信息的处理、退出登录的处理、刷新 token,都可以在一块完成。
- src/store/modules
- - user.js
// src/store/modules/user.js
import { loginUser, getProfile, registerUser } from '@/api/sys'
import md5 from 'md5'
import { message } from '@/libs'
import { LOGIN_TYPE_OAUTH_NO_REGISTER_CODE } from '@/constants'
export default {
namespaced: true,
state: () => ({
// 登录之后的 token
token: '',
// 获取用户信息
userInfo: {}
}),
mutations: {
/**
* 保存 token
*/
setToken(state, newToken) {
state.token = newToken
},
/**
* 保存用户信息
*/
setUserInfo(state, newInfo) {
state.userInfo = newInfo
}
},
actions: {
/**
* 注册
*/
async register(context, payload) {
const { password } = payload
// 注册
return await registerUser({
...payload,
password: password ? md5(password) : ''
})
},
/**
* 登录
*/
async login(context, payload) {
const { password } = payload
const data = await loginUser({
...payload,
password: password ? md5(password) : ''
})
// QQ 扫码登录,用户未注册
if (data.code === LOGIN_TYPE_OAUTH_NO_REGISTER_CODE) {
return data.code
}
context.commit('setToken', data.token)
context.dispatch('profile')
},
/**
* 获取用户信息
*/
async profile(context) {
const data = await getProfile()
context.commit('setUserInfo', data)
// 欢迎
message(
'success',
`欢迎您 ${
data.vipLevel
? '尊贵的 VIP' + data.vipLevel + ' 用户 ' + data.nickname
: data.nickname
} `,
6000
)
},
/**
* 退出登录
*/
logout(context) {
context.commit('setToken', '')
context.commit('setUserInfo', {})
// 退出登录之后,重新刷新下页面,
// 因为对于前台项目而言,用户是否登录(是否为 VIP)看到的数据可能不同
location.reload()
}
}
}
// 注意:在 src/store/index.js 中进行注册
npm i md5
07: 用户信息获取行为
企业级项目中常见的传递 token 方式:在 axios 请求头中
// src/utils/request.js
const service = axios.create({
baseURL: import.meta.env.VITE_BASE_API,
timeout: 5000
})
// 请求拦截器
service.interceptors.request.use(
(config) => {
// config.headers.icode = '你需要在这里填入你的 icode'
if (store.getters.token) {
// 如果token存在 注入token
config.headers.Authorization = `Bearer ${store.getters.token}`
}
return config // 必须返回配置
},
(error) => {
return Promise.reject(error)
}
)
// 代码在上一小节 src/store/modules/user.js 中。
08: 退出登录操作
// 代码在上一小节 src/store/modules/user.js 中。
// src/views/layout/components/header/header-my.vue
<script setup>
import { confirm } from '@/libs'
/**
* menu Item 点击事件,也可以根据其他的 key 作为判定,比如 name
*/
const onItemClick = (path) => {
// 有路径则进行路径跳转
if (path) {
// 配置跳转方式
store.commit('app/changeRouterType', 'push')
router.push(path)
return
}
// 无路径则为退出登录
confirm('您确定要退出登录吗?').then(() => {
// 退出登录不存在跳转路径
store.dispatch('user/logout')
})
}
</script>
09: token 超时处理
通常情况下 token 均具备时效性。在本文章中,token 失效后,服务端会返回 401.
当服务端返回 401 时,表示 token 超时,则需要重新登录。
对应的操作可以在 axios 的响应式拦截器中进行。
// src/utils/request.js
import axios from 'axios'
import store from '@/store'
import { message as $message } from '@/libs'
const service = axios.create({
baseURL: import.meta.env.VITE_BASE_API,
timeout: 5000
})
// 请求拦截器
service.interceptors.request.use(
(config) => {
// config.headers.icode = '你需要在这里填入你的 icode'
if (store.getters.token) {
// 如果token存在 注入token
config.headers.Authorization = `Bearer ${store.getters.token}`
}
return config // 必须返回配置
},
(error) => {
return Promise.reject(error)
}
)
// 响应拦截器
service.interceptors.response.use(
(response) => {
const { success, message, data } = response.data
// 要根据success的成功与否决定下面的操作
if (success) {
return data
} else {
$message('warn', message)
// TODO:业务错误
return Promise.reject(new Error(message))
}
},
// code 非 200 时,回调函数。
(error) => {
// 处理 token 超时问题
if (
error.response &&
error.response.data &&
error.response.data.code === 401
) {
// TODO: token超时
store.dispatch('user/logout')
}
$message('error', error.response.data.message)
// TODO: 提示错误消息
return Promise.reject(error)
}
)
export default service
10: 注册页面基本样式处理
- src/views/login-register
- - register
- - - index.vue
<template>
<div
class="relative h-screen bg-white dark:bg-zinc-800 text-center xl:bg-zinc-200"
>
<!-- 头部图标 -->
<header-vue></header-vue>
<!-- 表单区 -->
<div
class="block px-3 mt-4 dark:bg-zinc-800 xl:bg-white xl:w-[388px] xl:dark:bg-zinc-900 xl:m-auto xl:mt-8 xl:py-4 xl:rounded-sm xl:shadow-lg"
>
<h3
class="mb-2 font-semibold text-base text-main dark:text-zinc-300 hidden xl:block"
>
注册账号
</h3>
<!-- 表单 -->
<vee-form @submit="onRegister">
<!-- 用户名 -->
<vee-field
class="dark:bg-zinc-800 dark:text-zinc-400 border-b-zinc-400 border-b-[1px] w-full outline-0 pb-1 px-1 text-base focus:border-b-main dark:focus:border-b-zinc-200 xl:dark:bg-zinc-900"
name="username"
type="text"
placeholder="用户名"
autocomplete="on"
:rules="validateUsername"
v-model="regForm.username"
/>
<vee-error-message
class="text-sm text-red-600 block mt-0.5 text-left"
name="username"
>
</vee-error-message>
<!-- 密码 -->
<vee-field
class="dark:bg-zinc-800 dark:text-zinc-400 border-b-zinc-400 border-b-[1px] w-full outline-0 pb-1 px-1 text-base focus:border-b-main dark:focus:border-b-zinc-200 xl:dark:bg-zinc-900"
name="password"
type="password"
placeholder="密码"
autocomplete="on"
:rules="validatePassword"
v-model="regForm.password"
/>
<vee-error-message
class="text-sm text-red-600 block mt-0.5 text-left"
name="password"
>
</vee-error-message>
<!-- 确认密码 -->
<vee-field
class="dark:bg-zinc-800 dark:text-zinc-400 border-b-zinc-400 border-b-[1px] w-full outline-0 pb-1 px-1 text-base focus:border-b-main dark:focus:border-b-zinc-200 xl:dark:bg-zinc-900"
name="confirmPassword"
type="password"
placeholder="确认密码"
autocomplete="on"
rules="validateConfirmPassword:@password"
v-model="regForm.confirmPassword"
/>
<vee-error-message
class="text-sm text-red-600 block mt-0.5 text-left"
name="confirmPassword"
>
</vee-error-message>
<div class="pt-1 pb-3 leading-[0px] text-right">
<div class="mb-2">
<a
class="inline-block p-1 text-zinc-400 text-right dark:text-zinc-600 hover:text-zinc-600 dark:hover:text-zinc-400 text-sm duration-400 cursor-pointer"
target="__black"
@click="onToLogin"
>
去登录
</a>
</div>
<div class="text-center">
<a
class="text-zinc-400 dark:text-zinc-600 hover:text-zinc-600 dark:hover:text-zinc-400 text-sm duration-400"
href="https://m.imooc.com/newfaq?id=89"
target="__black"
>
注册即同意《慕课网注册协议》
</a>
</div>
</div>
<m-button
class="w-full dark:bg-zinc-900 xl:dark:bg-zinc-800"
:isActiveAnim="false"
:loading="loading"
>
立即注册
</m-button>
</vee-form>
</div>
</div>
</template>
<script setup>
import headerVue from '../components/header.vue'
import {
Form as VeeForm,
Field as VeeField,
ErrorMessage as VeeErrorMessage,
defineRule
} from 'vee-validate'
import {
validateUsername,
validatePassword,
validateConfirmPassword
} from '../validate'
import { LOGIN_TYPE_USERNAME } from '@/constants'
import { ref } from 'vue'
import { useStore } from 'vuex'
import { useRouter, useRoute } from 'vue-router'
const store = useStore()
const router = useRouter()
const route = useRoute()
/**
* 插入规则
*/
defineRule('validateConfirmPassword', validateConfirmPassword)
/**
* 进入登录页面
*/
const onToLogin = () => {
// 配置跳转方式
store.commit('app/changeRouterType', 'push')
router.push('/login')
}
// 数据源
const regForm = ref({
username: '',
password: '',
confirmPassword: ''
})
// loading
const loading = ref(false)
console.log(route)
/**
* 触发注册
*/
const onRegister = async () => {
loading.value = true
try {
const payload = {
username: regForm.value.username,
password: regForm.value.password
}
// 触发注册,携带第三方数据
await store.dispatch('user/register', {
...payload,
...route.query
})
// 注册成功,触发登录
await store.dispatch('user/login', {
...payload,
loginType: LOGIN_TYPE_USERNAME
})
} finally {
loading.value = false
}
router.push('/')
}
</script>
<style lang="scss" scoped></style>
确认密码 要关联到 密码,这样的关联操作 需要进行一个单独的注册。
// src/views/login-register/validate.js
/**
* 确认密码的表单校验
*/
export const validateConfirmPassword = (value, password) => {
if (value !== password[0]) {
return '两次密码输入必须一致'
}
return true
}
// register/index.vue 中使用代码
import { defineRule } from 'vee-validate'
import { validateConfirmPassword } from '../validate'
/**
* 插入规则
*/
defineRule('validateConfirmPassword', validateConfirmPassword)
<vee-field
placeholder="确认密码"
autocomplete="on"
rules="validateConfirmPassword:@password"
/>
11: 处理注册行为
// src/store/modules/user.js
export default {
……
actions: {
……
/**
* 注册
*/
async register(context, payload) {
const { password } = payload
// 注册
return await registerUser({
...payload,
password: password ? md5(password) : ''
})
},
}
}
// src/views/login-register/register/index.vue
// 代码在上一小节中
12: 总结
在本篇文章中,我们主要处理了两块内容:
1. 人类行为验证
1. 是什么
2. 目的
3. 实现原理
4. 构建方案
2. 表单验证原理 以及在实际开发中 通过 vee-validate 实现表单验证功能
登录处理完成之后,接下来我们就需要处理用户的信息展示和修改了。
在用户信息展示和修改中,我们将接触到新的通用组件和图片裁剪、上传的概念。