- //倒计时初始变量
- const codeNum = ref(60);
- // 定时器id
- let clearId: number;
- // 发送验证码
- const sendCode = async () => {
- // 防止下次点击 如果倒计时的时间不是60 就不执行下面逻辑
- if (codeNum.value != 60) return;
- // 掉接口
- const res = await getCode(mobile.value, "login");
- // 把定时器赋值给 变量clearId 目的:清除定时器
- clearId= setInterval(() => {
- // 每次 时间1s -1
- codeNum.value--;
- // 时间=0时 清除定时器
- if (codeNum.value == 0) {
- clearInterval(clearId);
- // 还原 倒计时60s
- codeNum.value = 60;
- }
- }, 1000);
- };
当然 这只是没有做过优化的一个发送验证码,如果要考虑点击连续点击或者离开页面时销毁定时器 还要加一些功能
(1)第一种方案,定义一个变量来控制 如果之前没有点击 再次点击不再执行
-
- <template>
- <a
- href="javascript:;"
- @click="sendCode"
- >{{ codeNum == 60 ? "发送验证码" : `(${codeNum})发送验证码` }}a>
- template>
(2)第二种方案. 让倒计时初始值为0 调用函数时在赋值为60 下次值大于0时同样不再执行,实现思路和第一种相似
- const codeNum = ref(0);
-
- const sendCode = async () => {
- if (codeNum.value > 0) return;
- isClickSend.value = true;
- const res = await getCode(mobile.value, "login");
- codeNum.value = 60
- if(clearId) clearInterval(clearId)
- clearId = setInterval(() => {
- codeNum.value--;
- if (codeNum.value == 0) {
- clearInterval(clearId);
- }
- }, 1000);
- };
其中没有对手机号进行校验 若需要则自己可以写校验规则,也可以参考当前使用的其他组件库使用
离开页面销毁定时器
- onMounted(() => {
- clearInterval(clearId)
- })
为什么要封装 验证码倒计时功能?
1. 为了下次再次使用时 直接copy代码达到复用
2. 在日常开发中可能 有很多场景都需要发送验证码 只是 接口一样 只是参数的type值不一样 例如 登录需要传login 注册需要传register 到时候只需要调用更换参数即可
新建composable/index.ts 准备放公共方法
- // 引用 发送的验证码类型
- import type { CodeType } from '@/type/user'
- // 引入接口
- import { getCode } from "@/api/login";
- import type { Ref } from 'vue'
- // 引入vant form类型 用来初始化form类型 可参考vant 若没有使用 则删除
- import type { FormProps, FormInstance } from 'vant';
-
- // 封装方法 只需要传入手机号、 type类型
- export const useSendCode = (mobile: Ref
, type: CodeType ) => { - // 定义定时器初始值为0
- const timer = ref(0)
- // 定义form变量 如果用了vant 记得要给vanForm 绑定ref
- const form = ref<FormInstance | null>() ;
- // 定义定时器id 为了清除定时器
- let timerId: number
- // 之后页面调用send方法来使用
- const send = async () => {
- // 第二次点击 大于0时 直接 return
- if (timer.value > 0) return
- // 校验 mobile字段 要和 van-field 中的name保持一直 否则校验失败 如果校验失败则不走下面代码 注意await
- await form.value?.validate('mobile')
- // 校验通过调用接口
- await getCode(mobile.value, type)
- // 赋值倒计时 可修改成自己需要的时间
- timer.value = 10
- // 如果之前id存在可清除
- if (timerId) clearInterval(timerId)
- // 赋值定时器id
- timerId = setInterval(() => {
- // 时间-1
- timer.value--
- // 倒计时结束 清除定时器
- if (timer.value == 0) clearInterval(timerId)
-
- }, 1000)
- }
- //
- onMounted(() => {
- clearInterval(timerId)
- })
- return { timer, send, form }
- }
由于代码中使用了插件 没有引入ref onMounted 需要可自行引入
页面中使用
-
-
- <template>
- <van-form ref="form" @submit="pwdLogin">
- <van-field
- v-model="mobile"
- name="mobile"
- maxlength="11"
- placeholder="请输入手机号"
- :rules="mobileRule"
- />
- van-form>
- ...
- <a href="javascript:;" @click="sendCode" >
- {{ timer == 0 ? "发送验证码" : `(${timer})后发送验证码` }}
- a>
- template>
补充 mobileRule
- import type { FieldRule } from 'vant'
-
- const mobileRules: FieldRule[] = [
- { required: true, message: '请输入手机号' },
- { pattern: /^1[3-9]\d{9}$/, message: '手机号格式不正确' }
- ]
-
- const passwordRules: FieldRule[] = [
- { required: true, message: '请输入密码' },
- { pattern: /^\w{8,24}$/, message: '密码需8-24个字符' }
- ]
-
- const codeRules: FieldRule[] = [
- { required: true, message: '请输入验证码' },
- { pattern: /^\d{6}$/, message: '验证码为6位数字' }
- ]
-
- export { mobileRules, passwordRules, codeRules }