vite2 + vue3实现curd(三):实现登录、注册
前言
实现需求
- 表单验证
- 防抖和节流
- 登录预验证
- 路由导航守卫
参考
开发步骤
向后端发送post请求前需进行表单验证
<script lang="ts">
export default {
data() {
return {
ruleForm: {
name: '',
pass: '',
},
flag: false, // 默认该按钮不是禁用状态
rules: {
name: [
{
required: true,
message: '请输入用户名!',
trigger: 'blur',
},
],
pass: [
{
required: true,
message: '请输入密码!',
trigger: 'blur',
},
],
},
}
},
}
</script>
对提交按钮进行防抖和节流操作:提交按钮点击一次后隔2秒才能再次点击,避免用户狂点,减轻服务器压力
<template>
<div>
<el-form-item>
<!-- 提交按钮 -->
<el-button type="primary" @click="submitForm('ruleForm')" :disabled='flag'
>Login</el-button
>
<el-button @click="resetForm('ruleForm')">Reset</el-button>
</el-form-item>
</div>
</template>
<script lang="ts">
export default {
data() {
return {
flag: false, // 默认该按钮不是禁用状态
methods: {
submitForm(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
console.log(this.ruleForm)
this.flag = true;
setTimeout(()=>{
console.log("可再次提交!")
this.flag= false;
}, 2000)
} else {
console.log('error submit!!')
return false
}
})
},
resetForm(formName) {
this.$refs[formName].resetFields()
},
},
}
</script>
element plus的表单中封装了validate函数,只有通过了表单验证才能向后端发送请求
<script lang="ts">
export default {
methods: {
submitForm(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
// 验证通过后在这里发送post请求
alert('submit!')
} else {
// 验证未通过的处理
console.log('error submit!!')
return false
}
})
},
resetForm(formName) {
this.$refs[formName].resetFields()
},
},
}
</script>
- 自定义验证规则时,在自定义的规则中添加
callback()
回调函数,否则验证完后永远无法进入validate函数,这里是一个坑
<script lang="ts">
export default {
data() {
const checkName = (rule, value, callback) => {
if (!value) {
return callback(new Error('请输入用户名!'))
} else {
callback()
}
}
const validatePass = (rule, value, callback) => {
if (value === '') {
callback(new Error('请输入密码!'))
} else {
if (this.ruleForm.checkPass !== '') {
this.$refs.ruleForm.validateField('checkPass')
}
callback()
}
}
const validatePass2 = (rule, value, callback) => {
if (value === '') {
callback(new Error('请再次输入密码!'))
} else if (value !== this.ruleForm.pass) {
callback(new Error("两次密码不一致!"))
} else {
callback()
}
}
return {
ruleForm: {
pass: '',
checkPass: '',
name: '',
},
rules: {
pass: [{ validator: validatePass, trigger: 'blur' }],
checkPass: [{ validator: validatePass2, trigger: 'blur' }],
name: [{ validator: checkName, trigger: 'blur' }],
},
flag: false, // 默认该按钮不是禁用状态
}
},
methods: {
submitForm(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
// 验证通过后的处理
console.log("success submit!")
} else {
console.log('error submit!!')
return false
}
})
},
resetForm(formName) {
this.$refs[formName].resetFields()
},
},
}
</script>
使用路由导航守卫:不能直接通过url跳转到控制台,只有当用户登录后才能访问控制台组件
<!-- 发送post请求进行登录,登录成功后将token保存到sessionStorage,同时跳转到控制台 -->
<script lang="ts">
export default {
methods: {
submitForm(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
console.log(this.ruleForm)
this.flag = true;
// 登录 post请求
const username = this.ruleForm.name;
const password = this.ruleForm.pass;
const reqData = {
username: username,
password,
}
this.$http.post("user/login", reqData).then((response)=>{
console.log(response)
// 将token保存到sessionStorage
window.sessionStorage.setItem('token', response.data)
// 跳转到home路由
this.$router.push('/consoleManage')
}).catch(error=>{console.error(error)});
// 登录结束
setTimeout(()=>{
console.log("可再次提交!")
this.flag= false;
}, 2000)
} else {
console.log('error submit!!')
return false
}
})
},
resetForm(formName) {
this.$refs[formName].resetFields()
},
},
}
</script>
- 在项目入口main.js中全局配置路由导航守卫
// router
import router from './route/index'
// 路由导航守卫
router.beforeEach((to, from, next) => {
// 要跳转到控制台页面时,先查看本地是否存在token,没有则返回登录页面
if(to.path === '/consoleManage') {
const tokenStr = window.sessionStorage.getItem('token')
if(!tokenStr) return next('/userLogin')
}
next()
})
-
登录时表单验证效果
-
登录成功后查看sessionStorage
-
退出登录
<template>
<div>
<el-button type="info" @click="logout">退出登录</el-button>
</div>
</template>
<script>
export default {
methods: {
logout() {
window.sessionStorage.clear(); // 清除sessionStorage中的token
this.$router.push("/login"); // 跳转到登录路由
}
}
};
</script>
- 注册用户实现源码
点击查看详情
<template>
<div class="box">
<img src="https://pic.imgdb.cn/item/61b812a02ab3f51d91b0a6ca.png" alt="">
<div class="register_box">
<span class="regiter_span">注册用户</span>
<el-form
ref="ruleForm"
:model="ruleForm"
status-icon
:rules="rules"
label-width="120px"
class="demo-ruleForm"
>
<span class="icon_avatar">
<el-icon><Avatar /></el-icon>
</span>
<el-form-item label="UserName" prop="name">
<el-input v-model.number="ruleForm.name"></el-input>
</el-form-item>
<span class="icon_unlock">
<el-icon><Unlock /></el-icon>
</span>
<el-form-item label="Password" prop="pass">
<el-input
v-model="ruleForm.pass"
type="password"
autocomplete="off"
></el-input>
</el-form-item>
<span class="icon_Sugar">
<el-icon><Sugar /></el-icon>
</span>
<el-form-item label="ReUsePass" prop="checkPass">
<el-input
v-model="ruleForm.checkPass"
type="password"
autocomplete="off"
></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm('ruleForm')" :disabled='flag'
>Submit</el-button
>
<el-button @click="resetForm('ruleForm')" class="but_re">Reset</el-button>
</el-form-item>
</el-form>
<span class="regiter_link">
<router-link to="/"> 已有账号,去登录</router-link>
</span>
</div>
</div>
</template>
<script lang="ts">
// icon
import { Avatar, Unlock, Sugar } from '@element-plus/icons'
export default {
components: {
Unlock,
Avatar,
Sugar
},
setup() {
},
data() {
const checkName = (rule, value, callback) => {
if (!value) {
return callback(new Error('请输入用户名!'))
} else {
callback()
}
}
const validatePass = (rule, value, callback) => {
if (value === '') {
callback(new Error('请输入密码!'))
} else {
if (this.ruleForm.checkPass !== '') {
this.$refs.ruleForm.validateField('checkPass')
}
callback()
}
}
const validatePass2 = (rule, value, callback) => {
if (value === '') {
callback(new Error('请再次输入密码!'))
} else if (value !== this.ruleForm.pass) {
callback(new Error("两次密码不一致!"))
} else {
callback()
}
}
return {
ruleForm: {
pass: '',
checkPass: '',
name: '',
},
rules: {
pass: [{ validator: validatePass, trigger: 'blur' }],
checkPass: [{ validator: validatePass2, trigger: 'blur' }],
name: [{ validator: checkName, trigger: 'blur' }],
},
flag: false, // 默认该按钮不是禁用状态
}
},
methods: {
submitForm(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
// console.log(this.ruleForm)
this.flag = true;
// 注册 post请求
const username = this.ruleForm.name;
const password = this.ruleForm.pass;
const reqData = {
username: username,
password,
}
this.$http.post("user/register", reqData).then((response)=>{
console.log(response)
if(response.code == 200 ) {
console.log("注册成功!")
// 跳转到home路由
this.$router.push('/userLogin')
}
}).catch(error=>{console.error(error)});
// 注册结束
setTimeout(()=>{
console.log("可再次提交!")
this.flag= false;
}, 2000)
} else {
console.log('error submit!!')
return false
}
})
},
resetForm(formName) {
this.$refs[formName].resetFields()
},
},
}
</script>
<style lang="less">
.box {
width: 100%;
height: 100%;
}
img {
float: left;
height: 810px;
width: 1556px;
opacity: 0.7;
}
.register_box {
width: 450px;
height: 380px;
border-radius: 5px;
border: 2px gray solid;
float: left;
position: absolute;
top: 200px;
left: 500px;
background-color: white;
opacity: 0.7;
}
.regiter_span {
font-size: larger;
position: relative;
top: 15px;
left: 180px;
}
.el-form {
position: relative;
top: 15px;
padding-right: 20px;
}
.icon_avatar{
position: relative;
top: 30px;
left: 20px;
}
.icon_unlock{
position: relative;
top: 30px;
left: 20px;
}
.icon_Sugar {
position: relative;
top: 30px;
left: 20px;
}
.regiter_link {
position: relative;
left: 305px;
top: 13px;
}
.el-button {
position: relative;
top: 35px;
left: 150px;
}
.el-button {
position: relative;
top: 5px;
left: 20px;
}
.but_re{
position: relative;
left: 70px;
}
</style>
- 表单验证效果
补充
- 发送post请求时报错:
415Unsupported media type
- 错误原因:
传给后端接口的参数格式不正确
- 解决错误:
这是因为我自己封装的axios有问题,注释掉如下代码即可