使用Canvas实现一个登陆验证码

341 阅读2分钟

前言

在我们编写登陆、注册页面的时候为了防止批量注册和登陆,此时就需要验证码来对前端登陆注册的接口进行保护。接下来我们使用canvas制作一个简单的登陆注册的验证码。

实现思路

  • 创建canvas画布并设置画布尺寸
  • 设置随机生成的画布背景颜色
  • 绘制画布干扰点
  • 随机生成4个合法字符绘制到画布上

准备工作

需要准备一些颜色或者写一个随机生成一些颜色的方法。

// 颜色表
const backgroundColor: string[] = [
  '#A98175',
  '#F9906F',
  '#F3D3E7',
  '#FCEFE8',
  '#FFFFFF',
  '#F9906F',
  '#FFB3A7',
  '#BCE672',
  '#88ADA6',
  '#C0EBD7',
  '#E0EEE8',
  '#E3F9FD',
  '#A1AFC9'
];
  // 生成一个随机颜色
  function randomColor(x: number, y: number) {
    const r = randomNum(x, y);
    const g = randomNum(x, y);
    const b = randomNum(x, y);
    return `rgb(${r},${g},${b})`;
  }

封装一个生成随机数的方法

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

随机生成一个合法字符方法,比如“0”和“o”那些比较难区分的字符排除掉

  function randomCharacter(): string {
  // 大小写a-z,0-9的正则表达式
    const regexp = new RegExp(/^[a-zA-Z\d]+$/)
    const random = randomNum(1, 122);
    const randomString = String.fromCharCode(random);
    const isTrue = randomString.search( regexp);
    const disableCharacter: string[] = ['l', 'I', 'o', 'O', '0', '1'];
    if (disableCharacter.includes(randomString)) {
      return randomCharacter();
    }
    if (isTrue === -1) {
      return randomCharacter();
    }
    return randomString;
  }

实现代码

先创建一个canvas标签并使用width,height属性设置画布的尺寸,

<canvas id="canvasScreen" width="150" height="40"></canvas>

使用id获取元素,并用getContext() 方法,该对象提供了用于在画布上绘图的方法和属性。 同时设置画板的背景颜色

function initCode() {
  const canvasScreen = document.getElementById('canvasScreen');
  const ctx = (canvasScreen as any).getContext('2d');
  //  随机获取颜色
  ctx.fillStyle = backgroundColor[Math.floor(Math.random() * 13)];
  // 绘制被填充的背景
  ctx.fillRect(0, 0, 150, 40);
  // 绘制背景的位置
  ctx.textBaseline = 'bottom';
  // 调用绘制方法
  randerCanvas();
  }

绘制随机生成字符的方法

// 绘制文字方法
  function drawText(print: string, i: number) {
    // 随机生成字体颜色
    ctx.fillStyle = randomColor(1, 125);
    // 随机设置字体大小
    ctx.font = `${randomNum(30, 40)}px SimHei`;
    // 字体偏移量
    const x = 30 * i;
    const y = 35;
    const deg = randomNum(-25, 25);
    // 修改坐标原点和旋转角度
    ctx.translate(x, y);
    ctx.rotate((deg * Math.PI) / 180);
    ctx.fillText(print, 0, 0);
    // 恢复坐标原点和旋转角度
    ctx.rotate((-deg * Math.PI) / 180);
    ctx.translate(-x, -y);
  }

在画布上绘制若干个干扰点

  function drawDot() {
    for (let i = 0; i < 20; i += 1) {
      ctx.fillStyle = randomColor(1, 255);
      ctx.beginPath();
      ctx.arc(randomNum(0, 180), randomNum(0, 60), 1, 0, 2 * Math.PI);
      ctx.fill();
    }
  }

最后调用之前写的方法渲染画布内容,在初始化时可以调用。

  function randerCanvas() {
    // 随机生成四个字符
    for (let i = 1; i < 5; i += 1) {
      const newText = randomCharacter();
      drawText(newText, i);
    }
    // 调用绘制干扰点方法
    drawDot();
  }

最后因为我使用的时vue3.2 setup语法糖,此时元素还没有被渲染,直接初始化会id获取不到当前元素报错,所以必须将方法放在onMounted()中。

onMounted(() => {
  initCode();
});

总结

这些就是实现登陆,注册验证验证码的实现方法。在实际开发中,一般情况下四位数的验证码是由后端返回的,只需要通过异步回调方法中重新调用绘制方法即可。