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
javascript 复制代码
// api.js
import axios from 'axios'

const api = axios.create({
  baseURL: 'http://localhost:3000', // 后端接口地址
  timeout: 5000,
})

export default api
将此文件引入到regs文件中
javascript 复制代码
// 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>
页面布局元素
javascript 复制代码
// 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>
具体功能模块
javascript 复制代码
// 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 + 1
    return 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.data
        if(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>
具体布局样式
javascript 复制代码
// 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>

效果展示:

动态验证码

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

大致思路:

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

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

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

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

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

成功后跳转到首页

逻辑很简单,自己试试看

相关推荐
加班是不可能的,除非双倍日工资4 小时前
css预编译器实现星空背景图
前端·css·vue3
wyiyiyi5 小时前
【Web后端】Django、flask及其场景——以构建系统原型为例
前端·数据库·后端·python·django·flask
gnip5 小时前
vite和webpack打包结构控制
前端·javascript
excel5 小时前
在二维 Canvas 中模拟三角形绕 X、Y 轴旋转
前端
阿华的代码王国6 小时前
【Android】RecyclerView复用CheckBox的异常状态
android·xml·java·前端·后端
一条上岸小咸鱼6 小时前
Kotlin 基本数据类型(三):Booleans、Characters
android·前端·kotlin
Jimmy6 小时前
AI 代理是什么,其有助于我们实现更智能编程
前端·后端·ai编程
草梅友仁6 小时前
草梅 Auth 1.4.0 发布与 ESLint v9 更新 | 2025 年第 33 周草梅周报
vue.js·github·nuxt.js
ZXT6 小时前
promise & async await总结
前端
Jerry说前后端6 小时前
RecyclerView 性能优化:从原理到实践的深度优化方案
android·前端·性能优化