vue3:八、登录界面实现-忘记密码

server/2025/3/17 21:54:39/

该文章实现登录界面的忘记密码功能,点击忘记密码文本,打开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:字符串类型,用于设置对话框的标题
javascript">const props =defineProps({showDialog:{type:Boolean,default:false},title:{type:String,default:''}
})

 定义emit,用于触发自定义事件

  • defineEmits:定义组件可以触发的自定义事件
  • ['update:showDialog']:数组,列出了组件可以触发的事件名称。这里是update:showDialog事件,表示组件可以触发update:showDialog事件
javascript">//定义emit,触发自定义事件
const emit = defineEmits(['update:showDialog']);

根据父组件传递的参数,控制组件的显示与隐藏

首先引入计算属性

javascript">import { computed, ref } from 'vue'

方法写入 

javascript">//定义一个计算属性,根据接收的父组件的传值值,控制dialog的显示与隐藏
const dialogVisible = computed({get(){return props.showDialog},set(val){emit('update:showDialog',val)}
})

5、登录页面引入组件

①引入组件

javascript">import ForgetForm from '@/components/ForgetForm.vue'

②写入点击事件

<span class="forget" @click="forgetDialog = true">忘记密码</span>

③定义变量

javascript">//记住密码
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为数字验证码
javascript">//表单提交
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如下

javascript">// 封装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

javascript">import { post } from '@/utils/request';// 发送短信-重置密码
export function repwdsms(data) {return post('/sms/repwdsms', data); 
}

③验证码-手机验证码发送apifox

新建接口,写入参数phone

写入期望

④验证码-验证码的发送

  • 设置验证码变量,定义默认值为0
  • 定义一个定时器,默认为空
  • 写入验证码方法
    • 首先写入手机号的规则,如果当手机号满足规则时,才执行方法,否则报错
    • 手机号正确:发送请求,如果请求成功,进行提示,并且使用setInterval开始倒计时

引入发送验证码方法 

javascript">import { repwdsms } from '@/api/sms'

 发送验证码

javascript">//设置验证码倒计时,默认为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秒倒计时,设置一个定时器,每秒减1seconds.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

新建接口,写入参数密码,确认密码,手机号,验证码四个参数

新建期望

建立重置密码成功的期望

⑦提交-提交表单

请求成功,返回提示信息,并且隐藏对话框;如果失败就返回提示信息

javascript">//提交表单
const submitForm = async (formEl) => {if (!formEl) returnawait 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) returnawait formEl.validate((valid, fields) => {if (valid) {console.log('submit!');// 1、请求登录接口进行登录// 参数为ruleFormconsole.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、设置tokensetToken(res.data.token)// 4、跳转页面router.push('/')}else {ElMessage.error(res.msg || '登录失败')}})} else {console.log('error submit!', fields)}})
}
//重置表单
const resetForm = (formEl) => {if (!formEl) returnformEl.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) returnawait 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) returnformEl.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秒倒计时,设置一个定时器,每秒减1seconds.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

javascript">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

javascript">import { post } from '@/utils/request';// 发送短信-重置密码
export function repwdsms(data) {return post('/sms/repwdsms', data); 
}


http://www.ppmy.cn/server/175790.html

相关文章

《Operating System Concepts》阅读笔记:p272-p285

《Operating System Concepts》学习第 27 天&#xff0c;p272-p285 总结&#xff0c;总计 14 页。 一、技术总结 1.semaphore A semaphore S is an integer variable that, apart from initialization, is accessed only through two standard atomic operations: wait() an…

【人工智能】人工智能安全(AI Security)

人工智能安全&#xff08;AI Security&#xff09; 是指保障人工智能系统免受各种攻击、滥用和错误操作的措施与技术。随着人工智能的广泛应用&#xff0c;AI的安全性问题变得越来越重要。AI安全不仅关注系统本身的稳定性与安全性&#xff0c;还涉及到如何确保AI的决策和行为是…

五种最新优化算法(ALA、AE、DOA、GOA、OX)求解多个无人机协同路径规划(可以自定义无人机数量及起始点),MATLAB代码

一、算法简介 &#xff08;一&#xff09;阿尔法进化&#xff08;Alpha Evolution&#xff0c;AE&#xff09;算法 阿尔法进化&#xff08;Alpha Evolution&#xff0c;AE&#xff09;算法是2024年提出的一种新型进化算法&#xff0c;其核心在于通过自适应基向量和随机步长的…

群体智能优化算法-䲟鱼优化算法 (Remora Optimization Algorithm, ROA,含Matlab源代码)

摘要 䲟鱼优化算法&#xff08;Remora Optimization Algorithm&#xff0c;ROA&#xff09;是一种基于䲟鱼在海洋中寄生与捕食者间交互关系而提出的元启发式算法。通过模拟䲟鱼在宿主附近进行寄生、吸附和随机机动等行为&#xff0c;ROA 在全局与局部搜索之间取得平衡。本文提…

Windows安全日志Defender 的配置被修改5007

事件 ID 5007 的含义 当 Windows Defender 的配置&#xff08;如实时保护、扫描策略、排除项等&#xff09;被手动或通过策略修改时&#xff0c;系统会记录此事件。可能的原因包括&#xff1a; 手动修改&#xff1a;用户或管理员通过界面更改了 Defender 设置。组策略或脚本&…

Blender-MCP服务源码2-依赖分析

Blender-MCP服务源码2-依赖分析 有个大佬做了一个Blender-MCP源码&#xff0c;第一次提交代码是【2025年3月7号】今天是【2025年月15日】也就是刚过去一周的时间&#xff0c;所以想从0开始学习这个代码&#xff0c;了解一下大佬们的开发思路 1-核心知识点 from mcp.server.fas…

基于asp.net实现的连锁餐厅收银系统[包运行成功+永久免费答疑辅导]

基于ASP.NET实现的连锁餐厅收银系统背景&#xff0c;可以从以下几个方面进行阐述&#xff1a; 一、技术背景 ASP.NET框架的普及与优势&#xff1a; ASP.NET是微软开发的一种用于构建Web应用程序的框架&#xff0c;它基于.NET Framework&#xff0c;提供了丰富的类库和开发工具…

Matlab GPU加速技术

1. GPU 加速简介 &#xff08;1&#xff09;为什么使用 GPU 加速&#xff1f; CPU 擅长处理逻辑复杂的串行任务&#xff0c;而 GPU 拥有数千个流处理器&#xff0c;专为并行计算设计。对于大规模矩阵运算、深度学习训练或科学计算等任务&#xff0c;GPU 加速可将计算速度提升数…