vue3:八、登录界面实现-忘记密码
该文章实现登录界面的忘记密码功能,点击忘记密码文本,打开dialog对话框
一、页面效果
加入忘记密码,在记住密码的同一行中,实现flex-between
二、对话框实现
1、新建组件页面
2、引入dialog组件到组件页面
参考路径
Dialog 对话框 | Element Plus
找到对话框基本用法,复制相关代码
粘贴到新建的组件页面ForgetForm.vue
3、整理引入的代码
<template>
<el-dialog v-model="dialogVisible" title="Tips" width="30%">
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="dialogVisible = false">
提交
</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup>
import { ref } from 'vue'
const dialogVisible = ref(false)
</script>
<style scoped>
.dialog-footer button:first-child {
margin-right: 10px;
}
</style>
4、建立子组件父组件的关联
在dialog组件中,需要定义一个参数props用于接收父组件传值
- defineProps:声明组件可以接收的属性
- showDialog:布尔类型,控制对话框的显示与隐藏,默认为隐藏
- title:字符串类型,用于设置对话框的标题
const props =defineProps({
showDialog:{
type:Boolean,
default:false
},
title:{
type:String,
default:''
}
})
定义emit,用于触发自定义事件
- defineEmits:定义组件可以触发的自定义事件
- ['update:showDialog']:数组,列出了组件可以触发的事件名称。这里是update:showDialog事件,表示组件可以触发update:showDialog事件
//定义emit,触发自定义事件
const emit = defineEmits(['update:showDialog']);
根据父组件传递的参数,控制组件的显示与隐藏
首先引入计算属性
import { computed, ref } from 'vue'
方法写入
//定义一个计算属性,根据接收的父组件的传值值,控制dialog的显示与隐藏
const dialogVisible = computed({
get(){
return props.showDialog
},
set(val){
emit('update:showDialog',val)
}
})
5、登录页面引入组件
①引入组件
import ForgetForm from '@/components/ForgetForm.vue'
②写入点击事件
<span class="forget" @click="forgetDialog = true">忘记密码</span>
③定义变量
//记住密码
const forgetDialog = ref(false);
④组件写入
- title="找回密码"子传递的是字符串,所以直接title就行,传递对话框的名称
- :showDialog="forgetDialog"将子组件的显示状态绑定到forgetDialog变量上,也就是forgetDialog的值为啥就会传递给父组件的showDialog(布尔值)(这里是传递的是变量,所以用了:)
- @update:showDialog="(v) => (forgetDialog = v)",使用子组件的方法update:showDialog,监听子组件的显示状态,当子组件的显示状态改变时,将子组件的显示状态绑定到forgetDialog变量上,函数控制子组件是否显示
<ForgetForm title="找回密码" :showDialog="forgetDialog" @update:showDialog="(v)=>(forgetDialog = v)"></ForgetForm>
⑤对话框正常显示确认
三、找回密码功能实现
主要实现密码、二次输入密码,手机号输入,验证码填入功能。
实现密码、手机号、验证码的规范;密码与二次输入的密码是否保持一致;验证码接收的倒计时效果等
1、视图层
①页面效果
②代码
ForgetForm.vue
- 在dialog中使用el表单,增加密码框(密码加密显示用 show-password属性 )、确认密码框、手机号输入框(使用number框),验证码输入框(使用number框)
- 在验证码获取时:需要获取按钮+倒计时显示
- 底部按钮:提交按钮+重置按钮+取消按钮
<template>
<el-dialog v-model="dialogVisible" :title="title" width="30%">
<el-form ref="ruleFormRef" style="max-width: 600px" :model="ruleForm" :rules="rules" label-width="auto"
class="demo-ruleForm" :size="formSize" status-icon>
<el-form-item label="新密码" prop="password">
<el-input show-password v-model="ruleForm.password" />
</el-form-item>
<el-form-item label="确认密码" prop="re_password">
<el-input show-password v-model="ruleForm.re_password" />
</el-form-item>
<el-form-item label="手机号" prop="phone">
<el-input v-model.number="ruleForm.phone" />
</el-form-item>
<el-form-item label="验证码" prop="code" class="flex flex-between">
<el-input style="width:75%" v-model.number="ruleForm.code" />
<el-button type="primary" @click="sendSms" style="width:22%" :disabled="seconds > 0">
<span v-if="seconds > 0">{{ seconds }}</span>
<span v-else>发送验证码</span>
</el-button>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button @click="resetForm(ruleFormRef)">重置</el-button>
<el-button type="primary" @click="submitForm(ruleFormRef)">
提交
</el-button>
</div>
</template>
</el-dialog>
</template>
2、样式层
对按钮曾进行了一个右侧的外边距设置
<style scoped>
.dialog-footer button:first-child {
margin-right: 10px;
}
</style>
3、逻辑层
①基本表单数据
- 首先定义四个表单数据密码:password,确认密码:re_password,手机号:phone,验证码:code
- 验证规则的写法:
- 密码的写法可以和登录页面一致(由于确认密码的验证规则和密码的规则一致,所以可以定义一个数组专门存入统一规则)
- 确认密码:首先引入写入的规则,然后还需要加入是否和密码输入的一致
- 手机号:通过pattern写入正则,按照手机号的正确格式
- 验证码:通过pattern写入正则,输入6为数字验证码
//表单提交
const formSize = ref('default')
const ruleFormRef = ref()
const ruleForm = reactive({
password: '',
re_password: '',
phone: '',
code: '',
})
const psdrule = [
{ required: true, message: '请输入密码', trigger: 'blur' },
{ min: 6, max: 20, message: '长度请在6-20之间', trigger: 'blur' },
{ pattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]+$/, message: '密码必须包含大、小写字母、数字和特殊字符', trigger: 'blur' }
];
const rules = reactive({
password: psdrule,
re_password: [
...psdrule,
{
validator: (rule, value, callback) => {
if (value != ruleForm.password) {
callback(new Error("两次输入密码不一致"))
}
else {
callback();
}
}, trigger: 'blur'
}
],
phone: [
{ required: true, message: '请输入手机号', trigger: 'blur' },
//1[3-9]\d{9}:手机号为1 + 3-9取一位 + 9位
{ pattern: /^1[3-9]\d{9}$/, message: '手机号格式不正确', trigger: 'blur' }
],
code: [
{ required: true, message: '请输入验证码', trigger: 'blur' },
// \d{6} 表示6位数字
{ pattern: /^\d{6}$/, message: '验证码格式不正确', trigger: 'blur' }
]
})
②验证码-定义发送验证码的api
新建一个关于发送验证码的api页面,这里是src/api/sms.js
(其实可以参见之前的文章)可以统一一下请求和方法:
vue3:request.js中请求方法,api封装请求,方法请求-CSDN博客
这里使用的请求方法采用的是request.js如下
// 封装GET请求
export const get = (url, params = {}) => {
return request.get(url, { params });
};
// 封装POST请求
export const post = (url, data = {}) => {
return request.post(url, data);
};
// 导出request实例
export default request;
src/api/sms.js
import { post } from '@/utils/request';
// 发送短信-重置密码
export function repwdsms(data) {
return post('/sms/repwdsms', data);
}
③验证码-手机验证码发送apifox
新建接口,写入参数phone
写入期望
④验证码-验证码的发送
- 设置验证码变量,定义默认值为0
- 定义一个定时器,默认为空
- 写入验证码方法
- 首先写入手机号的规则,如果当手机号满足规则时,才执行方法,否则报错
- 手机号正确:发送请求,如果请求成功,进行提示,并且使用setInterval开始倒计时
引入发送验证码方法
import { repwdsms } from '@/api/sms'
发送验证码
//设置验证码倒计时,默认为0秒
const seconds = ref(0);
//设置一个为空的定时器
let timer = null;
//发送验证码
const sendSms = () => {
//手机号规则
const phoneRule = /^1[3-9]\d{9}$/;
console.log(phoneRule.test(ruleForm.phone))
if (!phoneRule.test(ruleForm.phone)) {
ElMessage.error("手机号格式不正确");
return
}
else {
//发送请求
repwdsms({
phone: ruleForm.phone
}).then(res => {
if (res.code == 1) {
//设置验证码为60秒倒计时,设置一个定时器,每秒减1
seconds.value = 60;
//如果timer存在就清除这个定时器,然后在执行定时器操作
timer && clearInterval(timer);
timer = setInterval(() => {
seconds.value--;
if (seconds.value == 0) {
clearInterval(timer);
}
}, 1000);
ElMessage.success(res.msg || "验证码发送成功");
}
else {
ElMessage.error(res.msg || "验证码发送失败");
}
})
}
}
⑤ 提交-定义提交表单的api
新建一个关于发送验证码的api页面,这里是src/api/sms.js
⑥提交-提交表单apifox
新建接口,写入参数密码,确认密码,手机号,验证码四个参数
新建期望
建立重置密码成功的期望
⑦提交-提交表单
请求成功,返回提示信息,并且隐藏对话框;如果失败就返回提示信息
//提交表单
const submitForm = async (formEl) => {
if (!formEl) return
await formEl.validate((valid, fields) => {
if (valid) {
repwd(ruleForm).then(res => {
if(res.code ==1){
ElMessage.success(res.msg || '修改成功')
dialogVisible.value = false;//隐藏对话框
}
else{
ElMessage.error(res.msg || '修改失败')
}
})
} else {
console.log('error submit!', fields)
}
})
}
四、完整代码
1、登录页面
路径:src/views/LoginView.vue
<template>
<div class="page_all flex flex-center">
<div class="login_all flex flex-between">
<div class="login_left flex flex-center"><img src="/public/img/login.png"></div>
<div class="login_right flex flex-center flex-column">
<div class="form flex flex-center flex-column">
<div class="title flex flex-center">CMS管理系统</div>
<el-form ref="ruleFormRef" :model="ruleForm" :rules="rules" class="el-form demo-ruleForm"
:size="formSize" status-icon>
<el-form-item prop="username">
<el-input v-model="ruleForm.username" placeholder="请输入账号" />
</el-form-item>
<el-form-item prop="password">
<el-input v-model="ruleForm.password" show-password placeholder="请输入密码" />
</el-form-item>
<el-form-item class="checkbox flex flex-between">
<el-checkbox label="记住密码" v-model="remember" />
<span class="forget" @click="forgetDialog = true">忘记密码</span>
</el-form-item>
<el-form-item class="btn-group">
<el-button type="primary" @click="submitForm(ruleFormRef)">
登录
</el-button>
<el-button @click="resetForm(ruleFormRef)">重置</el-button>
</el-form-item>
</el-form>
</div>
</div>
</div>
</div>
<ForgetForm title="找回密码" :showDialog="forgetDialog" @update:showDialog="(v)=>(forgetDialog = v)"></ForgetForm>
</template>
<script setup>
//引入方法
import { reactive, ref } from 'vue'
import { login } from '@/api/user'
import { setToken } from '@/utils/token'
import { useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'
import { getLoginInfo, setLoginInfo, removeLoginInfo } from '@/utils/logininfo'
import ForgetForm from '@/components/ForgetForm.vue'
const formSize = ref('default')
const ruleFormRef = ref()
const ruleForm = reactive({
username: '',
password: '',
})
//记住密码
const forgetDialog = ref(false);
//设置记住密码,默认为未选中
const remember = ref(false)
const loginInfo = getLoginInfo();
if(loginInfo){
ruleForm.username = loginInfo.username;
ruleForm.password = loginInfo.password;
remember.value = true;
}
//设置路由
const router = useRouter();
//设置验证规则
const rules = reactive({
username: [
{ required: true, message: '请输入账号', trigger: 'blur' },
{ min: 3, max: 10, message: '长度请在3-10之间', trigger: 'blur' },
],
password: [
{ required: true, message: '请输入密码', trigger: 'blur' },
{ min: 6, max: 20, message: '长度请在6-20之间', trigger: 'blur' },
{
validator: (rule, value, callback) => {
const passwordPattern = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]+$/;
if (!passwordPattern.test(value)) {
callback(new Error('密码必须包含大写字母、小写字母、数字和特殊字符'));
} else {
callback();
}
}, trigger: 'blur'
}
],
})
//表单提交
const submitForm = async (formEl) => {
if (!formEl) return
await formEl.validate((valid, fields) => {
if (valid) {
console.log('submit!');
// 1、请求登录接口进行登录
// 参数为ruleForm
console.log(ruleForm)
// 2、请求登录接口进行登录
login(ruleForm).then(res => {
if (res.code == 1) {
// 2、提示成功信息
ElMessage.success(res.msg || '登录成功')
//记住密码设置
console.log('记住密码?:', remember.value);
if(remember.value){
setLoginInfo({
username: ruleForm.username,
password: ruleForm.password
})
}else{
removeLoginInfo();
}
// return
// 3、设置token
setToken(res.data.token)
// 4、跳转页面
router.push('/')
}
else {
ElMessage.error(res.msg || '登录失败')
}
})
} else {
console.log('error submit!', fields)
}
})
}
//重置表单
const resetForm = (formEl) => {
if (!formEl) return
formEl.resetFields()
}
</script>
<style>
.page_all {
width: 100%;
height: 100vh;
background-color: #808cdd;
}
.login_all {
width: 50%;
height: 60%;
background-color: white;
}
.login_left {
width: 50%;
height: 98%;
}
.login_left img {
width: 95%;
height: 80%;
object-fit: contain;
}
.login_right {
width: 50%;
height: 100%;
}
.title {
font-size: 25px;
color: #646cff;
letter-spacing: 3px;
height: 20%;
}
.form {
flex: 1;
width: 90%;
}
.el-form {
width: 60%;
}
.checkbox{
margin-top: 20px;
}
.btn-group {
width: 100%;
}
.btn-group button {
width: 45%;
}
.el-form-item__content {
justify-content: space-between;
}
.forget{
color: #646cff;
font-size:90%;
text-decoration: underline;
cursor: default;
}
</style>
2、忘记密码对话框
路径:src/components/ForgetForm.vue
<template>
<el-dialog v-model="dialogVisible" :title="title" width="30%">
<el-form ref="ruleFormRef" style="max-width: 600px" :model="ruleForm" :rules="rules" label-width="auto"
class="demo-ruleForm" :size="formSize" status-icon>
<el-form-item label="新密码" prop="password">
<el-input show-password v-model="ruleForm.password" />
</el-form-item>
<el-form-item label="确认密码" prop="re_password">
<el-input show-password v-model="ruleForm.re_password" />
</el-form-item>
<el-form-item label="手机号" prop="phone">
<el-input v-model.number="ruleForm.phone" />
</el-form-item>
<el-form-item label="验证码" prop="code" class="flex flex-between">
<el-input style="width:75%" v-model.number="ruleForm.code" />
<el-button type="primary" @click="sendSms" style="width:22%" :disabled="seconds > 0">
<span v-if="seconds > 0">{{ seconds }}</span>
<span v-else>发送验证码</span>
</el-button>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button @click="resetForm(ruleFormRef)">重置</el-button>
<el-button type="primary" @click="submitForm(ruleFormRef)">
提交
</el-button>
</div>
</template>
</el-dialog>
</template>
<script setup>
import { computed, ref, reactive } from 'vue'
import { ElMessage } from 'element-plus'
import { repwdsms } from '@/api/sms'
import { repwd } from '@/api/user'
// 定义props,用于接收父组件传值
const props = defineProps({
showDialog: {
type: Boolean,
default: false
},
title: {
type: String,
default: ''
}
})
//定义emit,触发自定义事件
const emit = defineEmits(['update:showDialog']);
//定义一个计算属性,根据接收的父组件的传值值,控制dialog的显示与隐藏
const dialogVisible = computed({
get() {
return props.showDialog
},
set(val) {
emit('update:showDialog', val)
}
})
//表单提交
const formSize = ref('default')
const ruleFormRef = ref()
const ruleForm = reactive({
password: '',
re_password: '',
phone: '',
code: '',
})
const psdrule = [
{ required: true, message: '请输入密码', trigger: 'blur' },
{ min: 6, max: 20, message: '长度请在6-20之间', trigger: 'blur' },
{ pattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]+$/, message: '密码必须包含大、小写字母、数字和特殊字符', trigger: 'blur' }
];
const rules = reactive({
password: psdrule,
re_password: [
...psdrule,
{
validator: (rule, value, callback) => {
if (value != ruleForm.password) {
callback(new Error("两次输入密码不一致"))
}
else {
callback();
}
}, trigger: 'blur'
}
],
phone: [
{ required: true, message: '请输入手机号', trigger: 'blur' },
//1[3-9]\d{9}:手机号为1 + 3-9取一位 + 9位
{ pattern: /^1[3-9]\d{9}$/, message: '手机号格式不正确', trigger: 'blur' }
],
code: [
{ required: true, message: '请输入验证码', trigger: 'blur' },
// \d{6} 表示6位数字
{ pattern: /^\d{6}$/, message: '验证码格式不正确', trigger: 'blur' }
]
})
//提交表单
const submitForm = async (formEl) => {
if (!formEl) return
await formEl.validate((valid, fields) => {
if (valid) {
repwd(ruleForm).then(res => {
if(res.code ==1){
ElMessage.success(res.msg || '修改成功')
dialogVisible.value = false;//隐藏对话框
}
else{
ElMessage.error(res.msg || '修改失败')
}
})
} else {
console.log('error submit!', fields)
}
})
}
//重置表单
const resetForm = (formEl) => {
if (!formEl) return
formEl.resetFields()
}
//设置验证码倒计时,默认为0秒
const seconds = ref(0);
//设置一个为空的定时器
let timer = null;
//发送验证码
const sendSms = () => {
//手机号规则
const phoneRule = /^1[3-9]\d{9}$/;
console.log(phoneRule.test(ruleForm.phone))
if (!phoneRule.test(ruleForm.phone)) {
ElMessage.error("手机号格式不正确");
return
}
else {
//发送请求
repwdsms({
phone: ruleForm.phone
}).then(res => {
if (res.code == 1) {
//设置验证码为60秒倒计时,设置一个定时器,每秒减1
seconds.value = 60;
//如果timer存在就清除这个定时器,然后在执行定时器操作
timer && clearInterval(timer);
timer = setInterval(() => {
seconds.value--;
if (seconds.value == 0) {
clearInterval(timer);
}
}, 1000);
ElMessage.success(res.msg || "验证码发送成功");
}
else {
ElMessage.error(res.msg || "验证码发送失败");
}
})
}
}
</script>
<style scoped>
.dialog-footer button:first-child {
margin-right: 10px;
}
</style>
3、关于用户的api
路径:src/api/user.js
import { post } from '@/utils/request';
// 登录
export function login(data) {
return post('/user/login', data);
}
//重置密码-通过手机号
export function repwd(data) {
return post('/user/repassword', data);
}
4、关于验证码的api
路径:src/api/sms.js
import { post } from '@/utils/request';
// 发送短信-重置密码
export function repwdsms(data) {
return post('/sms/repwdsms', data);
}
原文地址:https://blog.csdn.net/weixin_46001736/article/details/146279077
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.kler.cn/a/586630.html 如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.kler.cn/a/586630.html 如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!