vue3动态验证码

首先下载了vant4组件库,element-plus组件库,配置了路由,及接口的封装

element-plus组件库可全局配置:快速开始 | Element Plus

vant4组件库,我是按需引入:Vant 4 - A lightweight, customizable Vue UI library for mobile web apps.

封装api接口,例如utils/api.js
// api.js
import axios from 'axios'const api = axios.create({baseURL: 'http://localhost:3000', // 后端接口地址timeout: 5000,
})export default api
将此文件引入到regs文件中
// Sidentify.vue
<template><div class="s-canvas"><canvas id="s-canvas" :width="props.contentWidth" :height="props.contentHeight"></canvas></div></template><script setup>import { onMounted, watch } from 'vue'const props = defineProps({identifyCode: {type: String,default: '1234'},fontSizeMin: {type: Number,default: 25},fontSizeMax: {type: Number,default: 35},backgroundColorMin: {type: Number,default: 255},backgroundColorMax: {type: Number,default: 255},colorMin: {type: Number,default: 0},colorMax: {type: Number,default: 160},lineColorMin: {type: Number,default: 40},lineColorMax: {type: Number,default: 180},dotColorMin: {type: Number,default: 0},dotColorMax: {type: Number,default: 255},contentWidth: {type: Number,default: 112},contentHeight: {type: Number,default: 40}})// 生成一个随机数const randomNum = (min, max) => {return Math.floor(Math.random() * (max - min) + min)}// 生成一个随机的颜色const randomColor = (min, max) => {let r = randomNum(min, max)let g = randomNum(min, max)let b = randomNum(min, max)return 'rgb(' + r + ',' + g + ',' + b + ')'}// 绘制干扰线const drawLine = (ctx) => {for (let i = 0; i < 5; i++) {ctx.strokeStyle = randomColor(props.lineColorMin, props.lineColorMax)ctx.beginPath()ctx.moveTo(randomNum(0, props.contentWidth), randomNum(0, props.contentHeight))ctx.lineTo(randomNum(0, props.contentWidth), randomNum(0, props.contentHeight))ctx.stroke()}}//在画布上显示数据const drawText = (ctx, txt, i) => {ctx.fillStyle = randomColor(props.colorMin, props.colorMax)ctx.font = randomNum(props.fontSizeMin, props.fontSizeMax) + 'px SimHei'let x = (i + 1) * (props.contentWidth / (props.identifyCode.length + 1))let y = randomNum(props.fontSizeMax, props.contentHeight - 5)var deg = randomNum(-45, 45)// 修改坐标原点和旋转角度ctx.translate(x, y)ctx.rotate((deg * Math.PI) / 180)ctx.fillText(txt, 0, 0)// 恢复坐标原点和旋转角度ctx.rotate((-deg * Math.PI) / 180)ctx.translate(-x, -y)}// 绘制干扰点const drawDot = (ctx) => {for (let i = 0; i < 80; i++) {ctx.fillStyle = randomColor(0, 255)ctx.beginPath()ctx.arc(randomNum(0, props.contentWidth), randomNum(0, props.contentHeight), 1, 0, 2 * Math.PI)ctx.fill()}}//画图const drawPic = () => {let canvas = document.getElementById('s-canvas')let ctx = canvas.getContext('2d')ctx.textBaseline = 'bottom'// 绘制背景ctx.fillStyle = randomColor(props.backgroundColorMin, props.backgroundColorMax)ctx.fillRect(0, 0, props.contentWidth, props.contentHeight)// 绘制文字for (let i = 0; i < props.identifyCode.length; i++) {drawText(ctx, props.identifyCode[i], i)}drawLine(ctx)drawDot(ctx)}//组件挂载onMounted(() => {drawPic()})// 监听watch(() => props.identifyCode,() => {drawPic()})</script><style scoped lang="scss">.s-canvas {cursor: pointer;}</style>
页面布局元素
// regs.vue
<template><div class="reg-all"><div class="reg-tu">123</div><div class="reg-bt"><h1>注册</h1></div><van-form @submit="onSubmit" class="reg-login"><van-cell-group inset><van-field v-model="phone" name="手机号" label="手机号" placeholder="手机号":rules="[{ required: true, message: '请填写手机号' }]" /><van-field v-model="password" name="password" label="密码" placeholder="密码":rules="[{ required: true, message: '请填写密码' }]" /><van-field v-model="code" type="code" name="验证码" label="验证码" placeholder="验证码":rules="[{ required: true, message: '请填写验证码' }]" /><div class="reg-yzm" @click="refreshCode">// 引入的模块<SIdentify :identifyCode="identifyCode" class="code"></SIdentify></div></van-cell-group><div style="margin: 0 16px;"><van-button block type="primary" native-type="submit">提交</van-button></div></van-form><ul class="reg-bot"><li>忘记密码?</li><li @click="router.push('/log')">密码登录</li></ul></div>
</template>
具体功能模块
// regs.vue
<script setup>
// 引入的模块
import SIdentify from './Sidentify.vue'
// 引入的接口地址
import api from './utils/api'
import { ElMessage } from 'element-plus'
import { Form, Field, CellGroup } from 'vant';
import { useRouter } from 'vue-router'
import { ref, onMounted } from 'vue'
const router = useRouter()const phone = ref('');
const password = ref('');
const code = ref('');
const onSubmit = (values) => {regs()
};let identifyCode = ref('') //图形验证码
let identifyCodes = ref('1234567890abcdefjhijklinopqrsduvwxyz') //验证码出现的数字和字母//组件挂载
onMounted(() => {identifyCode.value = ''makeCode(identifyCodes.value, 4)
})// 生成随机数
const randomNum = (min, max) => {max = max + 1return Math.floor(Math.random() * (max - min) + min)
}
// 随机生成验证码字符串
const makeCode = (o, l) => {for (let i = 0; i < l; i++) {identifyCode.value += o[randomNum(0, o.length)]console.log('验证码:--',identifyCode.value);}
}
// 更新验证码
const refreshCode = () => {identifyCode.value = ''makeCode(identifyCodes.value, 4)
}
//登录
const regs = () => {//验证验证码不为空if (phone.value.length!==11) {ElMessage({ type: 'error', message: '手机号必须为11位' })return}if (password.value.length!==6) {ElMessage({ type: 'error', message: '密码必须为6位' })return}//验证验证码是否正确if (code.value != identifyCode.value) {ElMessage({ type: 'error', message: '验证码错误' })refreshCode()return} else {goes()  }
}const goes= async () => {try {const response = await api.post('/l/regs', {username: phone.value,password: password.value})const data=response.dataif(data.code==401){ElMessage({ type: 'error', message: data.message })}else{ElMessage({ type: 'success', message: 'go to 登录' })router.push('/log')}} catch (error) {console.error("登录失败:", error);}}
</script>
具体布局样式
// regs.vue
<style scoped lang="less"></style>
<style scoped >
.reg-all {text-align: center;
}.reg-bt {margin: 180px 0 30px 0;
}.reg-tu {background-color: aquamarine;height: 300px;border-radius: 50%;position: fixed;width: 375px;top: -150px;
}.reg-bot {display: flex;justify-content: space-between;li {padding: 10px 20px;font-size: 14px;/* color: red; */}
}.reg-yzm {width: 100px;height: 15px;background-color: red;position: relative;top: -40px;left: 220px;.code{height: 20px;}
}
</style>

效果展示:

 

动态验证码

 

前端提供,后端根据自己的需要自己写就好

大致思路:

注册时根据输入的手机号判断数据库中是否存在

如果存在就提示账户已存在

如果没有就接着注册自己的账号密码

登陆成功后跳转页面,跳到登录页

登录页输入刚刚创建的账号密码

成功后跳转到首页

逻辑很简单,自己试试看

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/234802.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MeterSphere files 任意文件读取漏洞复现 (CVE-2023-25573)

0x01 产品简介 MeterSphere 是一站式开源持续测试平台, 涵盖测试跟踪、接口测试、UI 测试和性能测试等功能,全面兼容 JMeter、Selenium 等主流开源标准。 0x02 漏洞概述 MeterSphere /api/jmeter/download/files 路径文件存在文件读取漏洞,攻击者可通过该漏洞读取系统重要…

[总线仲裁]

目录 一. 集中仲裁方式1.1 链式查询方式1.2 计数器查询方式1.3 独立请求方式 二. 分布式仲裁方式 总线仲裁是为了解决多个设备争用总线这个问题 \quad 一. 集中仲裁方式 \quad 集中仲裁方式: 就像是霸道总裁来决定谁先获得总线控制权 分布仲裁方式: 商量着谁先获得总线控制权 …

C语言实现链式队列

在C语言中&#xff0c;链式队列是一种使用链表实现的队列&#xff0c;它具有以下特点&#xff1a; 链式队列不需要预先分配固定大小的存储空间&#xff0c;可以动态地分配内存以适应不同大小的队列。链式队列可以无限扩展&#xff0c;因此不会出现队列满的情况。链式队列的入队…

国产670亿参数的DeepSeek:超越Llama2,全面开源

模型概述 DeepSeek&#xff0c;一款国产大型语言模型&#xff08;LLM&#xff09;&#xff0c;凭借其670亿参数的规模&#xff0c;正引领着人工智能领域的新浪潮。这款模型不仅在多项中英文公开评测榜单上超越了700亿参数的Llama 2&#xff0c;而且在推理、数学和编程能力方面…

JDK各个版本特性讲解-JDK16特性

JDK各个版本特性讲解-JDK16特性 一、JAVA16概述二、语法层面变化1.JEP 397&#xff1a;密封类&#xff08;第二次预览&#xff09;2.JEP 394&#xff1a;instanceof 的模式匹配3.JEP 395&#xff1a;记录4_JEP 390&#xff1a;基于值的类的警告 三、API层面变化1.JEP 338&#…

(备战2024)三天吃透Java面试八股文,面试通过率高达90%

什么样的求职者能够获得面试官的青睐&#xff1f;求职者需要准备哪些内容来面对形形色色的面试官&#xff1f;这两份资料是我在几十场面试中被面试官问到的问题&#xff0c;比其他复制粘贴的面试题强一百倍&#xff0c;堪称全网最强&#xff08;我不太喜欢“全网最强”这样的字…

车辆违规开启远光灯检测系统:融合YOLO-MS改进YOLOv8

1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 研究背景与意义 随着社会的不断发展和交通工具的普及&#xff0c;车辆违规行为成为了一个严重的问题。其中&#xff0c;车辆违规开启远光灯是一种常见的违规行为&#xff0c;给其…

贝蒂快扫雷~(C语言)

✨✨欢迎大家来到贝蒂大讲堂✨✨ ​​​​&#x1f388;&#x1f388;养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; 所属专栏&#xff1a;贝蒂的游戏 贝蒂的主页&#xff1a;Betty‘s blog 引言&#xff1a; 扫雷相信大家小时候到玩过吧&#xff0c;那…

数据库故障Waiting for table metadata lock

场景&#xff1a;早上来发现一个程序&#xff0c;链接mysql数据库有点问题&#xff0c;随后排查&#xff0c;因为容器在k8s里面。所以尝试重启了pod没有效果 一、重启pod: 这里是几种在Kubernetes中重启Pod的方法: 删除Pod,利用Deployment重建 kubectl delete pod mypodDepl…

python爬虫进阶篇:利用Scrapy爬取同花顺个股行情并发送邮件通知

一、前言 上篇笔记我记录了scrapy的环境搭建和项目创建和第一次demo测试。本篇我们来结合现实场景利用scrapy给我们带来便利。 有炒股或者其它理财产品的朋友经常会关心每日的个股走势&#xff0c;如果结合爬虫进行实时通知自己&#xff0c;并根据自己预想的行情进行邮件通知&…

字符设备的注册与注销实现

一. 简介 前面文章学习了 编写字符设备驱动框架&#xff0c;并加载驱动模块。了解了 一组注册与注销设备的函数。 了解了字符设备号的组成以及如何分配。文章地址如下&#xff1a; 字符设备驱动框架的编写-CSDN博客 字符设备驱动模块的编译-CSDN博客 字符设备注册函数与注…

跟着我学Python进阶篇:01.试用Python完成一些简单问题

往期文章 跟着我学Python基础篇&#xff1a;01.初露端倪 跟着我学Python基础篇&#xff1a;02.数字与字符串编程 跟着我学Python基础篇&#xff1a;03.选择结构 跟着我学Python基础篇&#xff1a;04.循环 跟着我学Python基础篇&#xff1a;05.函数 跟着我学Python基础篇&#…

Nodejs 第三十章(防盗链)

防盗链&#xff08;Hotlinking&#xff09;是指在网页或其他网络资源中&#xff0c;通过直接链接到其他网站上的图片、视频或其他媒体文件&#xff0c;从而显示在自己的网页上。这种行为通常会给被链接的网站带来额外的带宽消耗和资源浪费&#xff0c;而且可能侵犯了原始网站的…

听一些大神说测试前途是IT里最差的,真的是这样吗?

一&#xff1a;行业经历 测试行业爬模滚打7年&#xff0c;从点点点的功能测试到现在成为高级测试&#xff0c;工资也翻了几倍&#xff1b;个人觉得&#xff0c;测试的前景并不差&#xff0c;只要自己肯努力&#xff1b;我刚出来的时候是在鹅厂做外包的功能测试&#xff0c;天天…

c++ = default 和 = delete

default 和 delete 在C中&#xff0c;声明自定义的类型之后&#xff0c;编译器会默认生成一些成员函数&#xff0c;这些函数被称为默认函数。其中包括&#xff1a; &#xff08;1&#xff09;&#xff08;默认&#xff09;构造函数 &#xff08;2&#xff09;拷贝&#xff08…

ROS通信频率变慢、低于设定值的解决方法

1 问题 ROS gazebo以100Hz的频率发消息&#xff0c;触发A节点的回调函数&#xff0c;进而回调函数发送新消息到B节点。理论上新消息的频率也应该是100Hz。但是用rqt_topic查看发现&#xff0c;频率只有30多Hz。 2 解决 在初始化Subscriber的时候加上ros::TransportHints().…

【halcon深度学习之那些封装好的库函数】determine_dl_model_detection_param

determine_dl_model_detection_param 目标检测的数据准备过程中的有一个库函数determine_dl_model_detection_param “determine_dl_model_detection_param” 直译为 “确定深度学习模型检测参数”。 这个过程会自动针对给定数据集估算模型的某些高级参数&#xff0c;强烈建议…

C++命名空间(超详细)using namespace std

文章目录 前言一、为什么要有命名空间二、命名空间的定义1.正常定义2.嵌套定义3.多文件 三、命名空间的使用1.命名空间名称作用域限定符2.使用using将命名空间某个成员引入3.使用using namespace将整个命名空间引入 四、c标准库总结 前言 在本文章中&#xff0c;我们将要详细介…

Linux服务器nginx部署Vue前端(详细版)

提示&#xff1a;适用于前后端项目的部署 文章目录 前言一、打包前端文件二、下载和部署Nginx三、配置conf文件启动nginx 前言 搜索到这篇文章想必你已经对Nginx比较了解&#xff0c;我也不对Nginx进行介绍赘述了&#xff0c;只需要明白Nginx本身也是一个静态资源的服务器&…