首页 > 其他分享 >vue3 原生 JS canvas 封装获取验证码组件

vue3 原生 JS canvas 封装获取验证码组件

时间:2024-12-01 14:34:48浏览次数:11  
标签:canvas const props ctx 验证码 randomNum JS vue3 绘制

前言

由于开发中,产品有需求,要求开发一个可以自定义字符的随机获取4个字符的验证码组件,然后我就仿照流行的验证码功能写了一个

 运行效果

HTML
<template>
  <!-- 验证码画布容器,点击后会触发验证码刷新 -->
  <span class="s-canvas" @click="changeCode">
    <canvas
      id="s-canvas"
      :width="contentWidth"
      :height="contentHeight"
    ></canvas>
  </span>
</template>
JS
<script setup lang="ts">
import { ref, watch, onMounted, defineProps, defineEmits } from "vue";

// 定义组件的 props
const props = defineProps({
  // 默认的验证码字符集,包含数字和字母
  identifyCodes: {
    type: String,
    default: "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ",
  },
  // 字体最小值,用于生成随机字体大小
  fontSizeMin: {
    type: Number,
    default: 25,
  },
  // 字体最大值,用于生成随机字体大小
  fontSizeMax: {
    type: Number,
    default: 35,
  },
  // 背景色最小值,用于生成随机背景颜色
  backgroundColorMin: {
    type: Number,
    default: 200,
  },
  // 背景色最大值,用于生成随机背景颜色
  backgroundColorMax: {
    type: Number,
    default: 220,
  },
  // 干扰点的颜色最小值
  dotColorMin: {
    type: Number,
    default: 60,
  },
  // 干扰点的颜色最大值
  dotColorMax: {
    type: Number,
    default: 120,
  },
  // 验证码容器的宽度
  contentWidth: {
    type: Number,
    default: 100,
  },
  // 验证码容器的高度
  contentHeight: {
    type: Number,
    default: 44,
  },
});

// 定义 emits,用于向父组件发送验证码变化事件
const emit = defineEmits<{
  (event: "update:changeCode", identifyCode: string): void;
}>();

// 创建响应式的验证码内容
const identifyCode = ref("");

// 监听 identifyCode 的变化,重新绘制验证码
watch(identifyCode, () => {
  // 每次验证码变化时,重新绘制验证码
  drawPic();
});

// 在组件挂载时,生成初始验证码
onMounted(() => {
  // 生成4位随机验证码
  makeCode(props.identifyCodes, 4);
  drawPic();
});

// 生成一个指定范围内的随机整数
const randomNum = (min: number, max: number): number => {
  return Math.floor(Math.random() * (max - min) + min);
};

// 生成一个随机颜色,范围由 min 到 max
const randomColor = (min: number, max: number): string => {
  const r = randomNum(min, max); // 红色值
  const g = randomNum(min, max); // 绿色值
  const b = randomNum(min, max); // 蓝色值
  return `rgb(${r},${g},${b})`; // 返回 RGB 颜色字符串
};

// 绘制验证码的图片
const drawPic = () => {
  const canvas = document.getElementById("s-canvas") as HTMLCanvasElement;
  // 获取画布上下文,进行绘制
  const 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 < identifyCode.value.length; i++) {
    drawText(ctx, identifyCode.value[i], i);
  }

  // 绘制干扰线
  drawLine(ctx);

  // 绘制干扰点
  drawDot(ctx);
};

// 绘制验证码文字
const drawText = (ctx: CanvasRenderingContext2D, txt: string, i: number) => {
  // 随机生成文字颜色
  ctx.fillStyle = randomColor(50, 160);
  // 随机生成字体大小
  ctx.font = `${randomNum(props.fontSizeMin, props.fontSizeMax)}px SimHei`;
  // 计算每个字符的 x 坐标
  const x = (i + 1) * (props.contentWidth / (identifyCode.value.length + 1));
  // 计算字符的 y 坐标
  const y = randomNum(props.fontSizeMax, props.contentHeight - 5);
  // 随机生成字符旋转角度
  const deg = randomNum(-30, 30);

  // 修改坐标原点并旋转
  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 drawLine = (ctx: CanvasRenderingContext2D) => {
  for (let i = 0; i < 4; i++) {
    // 绘制 4 条干扰线
    ctx.strokeStyle = randomColor(100, 200);
    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 drawDot = (ctx: CanvasRenderingContext2D) => {
  for (let i = 0; i < 30; i++) {
    // 绘制 30 个干扰点

    // 随机生成点的颜色
    ctx.fillStyle = randomColor(0, 255);
    ctx.beginPath();
    ctx.arc(
      // 圆心 x 坐标
      randomNum(0, props.contentWidth),
      // 圆心 y 坐标
      randomNum(0, props.contentHeight),
      // 半径
      1,
      // 起始角度
      0,
      // 结束角度
      2 * Math.PI
    );
    // 填充圆点
    ctx.fill();
  }
};

// 切换验证码
const changeCode = () => {
  // 清空当前验证码
  identifyCode.value = "";
  // 重新生成验证码
  makeCode(props.identifyCodes, 4);
};

// 生成验证码
const makeCode = (e: string, n: number) => {
  // 清空当前验证码内容
  identifyCode.value = "";
  for (let i = 0; i < n; i++) {
    // 生成 n 位验证码  从字符集中随机选取字符
    identifyCode.value += e[randomNum(0, e.length)];
  }
  // 向父组件发送新的验证码
  emit("update:changeCode", identifyCode.value);
};
</script>
组件使用
 <number-code
    :identifyCodes="'1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ'"  
    :fontSizeMin=30  
    :fontSizeMax=50   
    :contentWidth=150 
    :contentHeight=50 
  />
获取验证码API
changeCode监听验证码变化事件val
传参参数
identifyCodes自定义验证码字符集(随机取4个)string-
fontSizeMin字体最小值(px)number25
fontSizeMax字体最大值(px)number35
contentWidth容器宽度(px)number100
contentHeight容器高度(px)number45
backgroundColorMin背景色最小值(RGB值范围)number200
backgroundColorMax背景色最大值(RGB值范围)number220
dotColorMin干扰点颜色最小值(RGB值范围)number60
dotColorMax干扰点颜色最大值(RGB值范围)number120

标签:canvas,const,props,ctx,验证码,randomNum,JS,vue3,绘制
From: https://blog.csdn.net/weixin_55237137/article/details/144051316

相关文章

  • vue3 数字自增长组件
    前言当做数字大屏的时候,就需要做一个数字传入后,可以自增长的组件,可以根据数据大小算每一次跳动的数字运行效果 会从0开始自动增加到9000(录屏好麻烦)HTML<template><divclass="counter"><div:style="{color:fontColor,fontSize:fontSize}"><span......
  • node.js毕设乐昌教育局信息管理系统 程序+论文
    本系统(程序+源码+数据库+调试部署+开发环境)带文档lw万字以上,文末可获取源码系统程序文件列表开题报告内容一、选题背景在当今数字化时代,信息管理系统在各个领域都发挥着至关重要的作用。在教育领域,信息管理系统有助于提高教育管理的效率和质量。关于教育局信息管理系统的......
  • node.js毕设陕西非物质文化遗产网站 程序+论文
    本系统(程序+源码+数据库+调试部署+开发环境)带文档lw万字以上,文末可获取源码系统程序文件列表开题报告内容一、选题背景在国内,随着对传统文化的重视度不断提高,非物质文化遗产的保护与传承受到广泛关注。关于陕西非物质文化遗产的研究,现有研究多集中在文化内涵、传承人的保......
  • node.js毕设体育馆在线预约管理系统程序+论文
    本系统(程序+源码+数据库+调试部署+开发环境)带文档lw万字以上,文末可获取源码系统程序文件列表开题报告内容一、选题背景关于体育馆在线预约管理系统的研究,现有研究多集中在大型综合性场馆的整体运营管理方面,专门针对包含会员、收银员、教练等多种角色以及场地、器材相关功......
  • node.js毕设体育活动信息平台_程序+论文
    本系统(程序+源码+数据库+调试部署+开发环境)带文档lw万字以上,文末可获取源码系统程序文件列表开题报告内容一、选题背景关于体育活动信息平台的研究,现有研究主要以体育赛事管理或体育健身APP等单一功能为主,专门针对整合多种体育活动相关信息(如学生、体测信息、体育场地、比......
  • node.js毕设体育系统程序+论文
    本系统(程序+源码+数据库+调试部署+开发环境)带文档lw万字以上,文末可获取源码系统程序文件列表开题报告内容一、选题背景关于体育系统的研究,现有研究主要集中在体育赛事的组织、运动员的训练等方面,专门针对涵盖多种功能如用户、影片类型(电视剧、电影、综艺、动漫等)以及体育......
  • node.js毕设体育用品库存管理系统程序+论文
    本系统(程序+源码+数据库+调试部署+开发环境)带文档lw万字以上,文末可获取源码系统程序文件列表开题报告内容一、选题背景在当今商业环境下,库存管理对于企业的运营和发展至关重要。关于体育用品库存管理系统的研究,现有研究主要以通用的库存管理理论和大型企业的库存管理实践......
  • Nuxt.js 应用中的 render:island 事件钩子
    title:Nuxt.js应用中的render:island事件钩子date:2024/12/1updated:2024/12/1author:cmdragonexcerpt:在Nuxt.js中,render:island钩子允许开发者在构建“岛屿”HTML之前进行处理和修改。此钩子为实现复杂的客户端交互和动态内容提供了基本支持,特别适合与服务器渲......
  • 开源低代码平台-Microi吾码-接口引擎实战:微信v3支付JSAPI下单
    Microi吾码-接口引擎实战:微信v3支付JSAPI下单简介预览图业务逻辑接口引擎代码Microi吾码-系列文档接口引擎实战-系列文档简介接口引擎与第三方平台对接无所不能,下一篇介绍对接微信支付回调(含签名验证)预览图业务逻辑参考微信支付官方文档:https://pay.weixin.qq......
  • HTML5系列(4)--Canvas 绘图详解
    前端技术探索系列:HTML5Canvas绘图详解......