快来和我一起做个验证码!

796 阅读5分钟

前言

小伙伴们在玩手机的时候是不是会经常遇到有时候需要输入验证码的操作,输过这么多次的验证码,有没有想过这个验证码是怎么做出来的呢?今天,小编就带大家一起动手来完成一个验证码的实现。快来一起试试吧。先给大家来看看效果:就是这样的

在完成验证码的制作之前,首先,咱们需要来了解一下Canvas技术

canvas是什么?

canvas技术是HTML5的一项重要特性,它提供了一种在网页上直接绘制图形的方法。通过 <canvas> 元素和JavaScript,咱们可以直接在网页上绘制图形、制作动画、处理图像等,而无需依赖任何外部插件(如Flash)。这使得Canvas成为了网页游戏开发、数据可视化、图形编辑器以及各种交互式应用的有力工具。

canvas最基本的步骤

<canvas id="myCanvas" width="400" height="400"></canvas>

1.创建Canvas元素: 在HTML文件中添加<canvas>标签,定义画布的宽和高。

let canvas = document.getElementById("canvas")
let ctx = canvas.getContext("2d")

2.获取Canvas上下文: 使用JavaScript获取到<canvas>元素,并通过getContext('2d')方法获取2D渲染上下文。这是进行绘图操作的基础。

其他操作

1.绘图操作: 使用上下文对象(ctx)进行各种绘图操作,如绘制形状、填充颜色、描边等。基本步骤通常包括:

开始路径:ctx.beginPath();

移动到起点:ctx.moveTo(x, y);

绘制线段/形状:如ctx.lineTo(x, y);ctx.arc(x, y, radius, startAngle, endAngle, counterclockwise);等。

关闭路径(如果需要封闭图形):ctx.closePath();

2.填充矩形: ctx.fillRect(0,0,100,100) 这行代码在canvas上绘制了一个填充的矩形。fillRect(x, y, width, height)方法接受四个参数,分别代表矩形的左上角坐标(x, y)以及矩形的宽度和高度。在这个例子中,矩形的左上角位于(0, 0),宽高都是100px,默认使用的是上下文的当前填充色(如果未指定,默认是黑色)。

3.设置描边颜色: ctx.strokeStyle = 'red' 这行代码设置了接下来要绘制图形的描边颜色为红色。strokeStyle属性控制了所有后续描边操作的颜色。

4.描边矩形: ctx.strokeRect(0,0,100,100) 最后这行代码在同样的位置(0, 0)绘制了一个宽度和高度都为100px的矩形的边框,颜色为之前设置的红色。strokeRect()方法只绘制边框,不填充内部。

其他高级操作

使用变换操作,如旋转、缩放、平移等,通过ctx.translate(), ctx.rotate(), ctx.scale()等方法。

了解这些基础操作了之后咱们就来动手实现咱们的验证码啦:

一、构建canvas画布

首先,我们需要构建一个Canvas画布。通过标签,创建一个绘图区域,来展示我们的验证码。

     <canvas id="canvas" width="120" height="40"></canvas>

二、增加背景色

大家在手机上输入验证码的时候是不是每次验证码的颜色都会不一样,都会有不一样的背景色,这个可以怎么设计呢?咱们可以通过Js随机生成背景色。利用RGB这种颜色模式,生成各种各样丰富多彩的背景色。

// 生成[min,max)之间的随机数
function randomNum(min, max) {
    return Math.floor(Math.random() * (max - min) + min)
}
// 生成随机颜色
function randomColor(min, max) {
    let r = randomNum(min, max)
    let g = randomNum(min, max)
    let b = randomNum(min, max)
    return `rgb(${r},${g},${b}`;
}
        
let canvas = document.getElementById("canvas");
let ctx = canvas.getContext("2d");

// 背景填充色 随机
ctx.fillStyle = randomColor(180, 230)
ctx.fillRect(0, 0, canvas.width, canvas.height)
  1. 生成[min,max)之间的随机数:定义了一个函数randomNum(min, max),它利用Math.random()生成0到1之间的随机数,然后通过计算将其转换为minmax之间的一个整数。
  2. 生成随机颜色:定义了函数randomColor(min, max),它分别调用randomNum(min, max)三次来获取红色(R)、绿色(G)、蓝色(B)的随机值,之后返回一个格式为rgb(r,g,b)的字符串,用于表示随机颜色。
  3. 获取Canvas元素和2D渲染上下文:通过document.getElementById("canvas")获取到页面上的canvas元素,并通过getContext("2d")获得2D绘图上下文。
  4. 填充背景色:使用之前定义的randomColor函数生成一个随机颜色,并将其作为fillStyle应用于ctx(。然后,通过fillRect(0, 0, canvas.width, canvas.height)方法填充整个Canvas区域为这个随机颜色。

三、增加随机验证码

接下来就是如何获取随机的验证码字符呢?咱们可以先定义一个字符池包含这26个大小写字母,然后通过for循坏迭代四次,获取到每个字符在进行设置,通过一系列随机操作(字符选择、字体大小、字体粗细、颜色、旋转角度),在HTML5 Canvas上绘制了四个随机分布、旋转和着色的字符。

let pool ="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
        //随机生成字符串
        let imgCode = "";
        for(let i=0;i<4;i++){
            const text = pool[randomNum(0,pool.length)]
            imgCode += text;
            //随机字体大小
            const fontSize = randomNum(18,40);
            //随机字体粗细
            const fontWeight = randomNum(300,700);
            //随机旋转角度
            const deg = randomNum(-30,30);
            ctx.font=`${fontSize}px SimHei`;
            ctx.textBaseline = "top";
            ctx.fillStyle = randomColor(80,160);
            ctx.save();//将当前状态封存入栈
            ctx.translate(15+i*30,15);
            ctx.rotate((deg*Math.PI)/180);
            ctx.fillText(text,-15+5,-15);
            ctx.restore();//将当前状态弹出栈
            //循环四次,出现四个随机字母
        }

四、增加干扰线和干扰点

验证码上除了数字和字母外,有时候就是好恶心还有一些干扰线和干扰点,增加验证码的安全性,以增加辨识难度,防止自动化软件的识别。这些又是如何实现的呢?

//绘制干扰线
        for(let i=0;i<3;i++){
            ctx.beginPath();
            ctx.moveTo(randomNum(0,canvas.width),randomNum(0,canvas.height));
            ctx.lineTo(randomNum(0,canvas.width),randomNum(0,canvas.height));
            ctx.strokeStyle = randomColor(100,230);
            ctx.closePath();
            ctx.stroke();
        }  

咱们通过让循环执行3次,每次生成一条从随机起点到随机终点的直线,颜色也为随机选取,这样做可以在验证码图像中添加几条无规律的线条,干扰机器视觉的识别。

//绘制干扰点
        for(let i=0;i<40;i++){
            ctx.beginPath();
            ctx.arc(randomNum(0,canvas.width),randomNum(0,canvas.height),1,0,2*Math.PI);
            ctx.fillStyle = randomColor(150,250);
            ctx.closePath();
            ctx.fill();
        }
    }

这个循环执行40次,每次在随机位置绘制一个半径为1像素的圆形(表现为一个点),颜色也是随机选取的较亮色调。对于每个干扰点,使用 ctx.fillRect(Math.random() * canvas.width, Math.random() * canvas.height, 1, 1) 在随机位置绘制一个像素大小的填充矩形,作为干扰点。这些点作为额外的视觉干扰元素散布在整个验证码图像上,使得自动化解析更加困难。

让咱们看看效果:

image-20240530004207691.png

最后,咱们再来增加一个功能onclick让咱们的验证码可以实现点击重新实现。

<canvas id="canvas" width="120" height="40" onclick="draw()"></canvas>

全部代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <canvas id="canvas" width="120" height="40" onclick="draw()"></canvas>
    <!-- <button onclick="draw()">验证</button> -->
    <script>
        let pool ="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"

        function randomNum(min,max) {
        return Math.floor(Math.random()*(max-min)+min);
        }
        function randomColor(min,max) {
            const r =randomNum(min,max);
            const g =randomNum(min,max);
            const b =randomNum(min,max);    
            return `rgb(${r},${g},${b})`;//返回rgb格式颜色
        }
        function draw() {
        let canvas = document.getElementById("canvas");
        let ctx = canvas.getContext("2d");
        //填充色 随机
        ctx.fillStyle = randomColor(180,230);
        ctx.fillRect(0,0,canvas.width,canvas.height);
        //随机生成字符串
        let imgCode = "";
        for(let i=0;i<4;i++){
            const text = pool[randomNum(0,pool.length)]
            imgCode += text;
            //随机字体大小
            const fontSize = randomNum(18,40);
            //随机字体粗细
            const fontWeight = randomNum(300,700);
            //随机旋转角度
            const deg = randomNum(-30,30);
            ctx.font=`${fontSize}px SimHei`;
            ctx.textBaseline = "top";
            ctx.fillStyle = randomColor(80,160);
            ctx.save();//将当前状态封存入栈
            ctx.translate(15+i*30,15);
            ctx.rotate((deg*Math.PI)/180);
            ctx.fillText(text,-15+5,-15);
            ctx.restore();//将当前状态弹出栈
            //循环四次,出现四个随机字母
        }
        //绘制干扰线
        for(let i=0;i<3;i++){
            ctx.beginPath();
            ctx.moveTo(randomNum(0,canvas.width),randomNum(0,canvas.height));
            ctx.lineTo(randomNum(0,canvas.width),randomNum(0,canvas.height));
            ctx.strokeStyle = randomColor(100,230);
            ctx.closePath();
            ctx.stroke();
        }
        //绘制干扰点
        for(let i=0;i<40;i++){
            ctx.beginPath();
            ctx.arc(randomNum(0,canvas.width),randomNum(0,canvas.height),1,0,2*Math.PI);
            ctx.fillStyle = randomColor(150,250);
            ctx.closePath();
            ctx.fill();
        }
    }
        draw();
    </script>
</body>
</html>

总结:

通过canvas技术咱们就可以构建一个自己的验证码啦,是不是感觉很有趣,快去试试吧。好啦,今天的分享就到这里啦。