前言
图形验证码
是一种常见的安全措施,用于区分人类用户和自动化软件(如机器人)。它通常以扭曲的字母和数字形式出现,这些字母和数字难以被光学字符识别技术解析。通过要求用户正确输入这些字符,网站能够有效防止垃圾邮件发送者、恶意登录尝试等行为。
今天向大家介绍如何使用canvas来创建一个简单的图形验证码生成器。实现的效果如下:
正文
HTML结构
首先,让我们来看一下HTML部分:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>验证码生成器</title>
</head>
<body>
<canvas id="canvas" width="120" height="40" onclick="draw()"></canvas>
<script>
// JavaScript代码将在这里
</script>
</body>
</html>
解释:我们实现这个验证码最关键的元素是<canvas>
标签。canvas
是一个HTML5元素,允许我们在网页上绘制图形。我们设置了它的宽度为120像素,高度为40像素,并且给它绑定了一个onclick事件处理函数draw() 。这意味着每当用户点击这个canvas时,都会调用draw() 函数来重新生成验证码。
JavaScript逻辑
接下来,我们来详细了解JavaScript代码。
随机数生成
首先,我们需要能够生成随机数。为此,我们定义了randomNum()
函数,它接收两个参数:最小值min和最大值max,然后返回在这两个值之间的随机整数,用于后面生成随机的背景颜色和验证码里面字符。
function randomNum(min, max) {
return Math.floor(Math.random() * (max - min) + min);
}
解释:Math.random() 生成0到1之间的数,我们通过乘以 (max - min)
再加上min
就是一个在max和min之间的数了(生成0是最小的数,生成1是最大的数),最后使用Math.floor()
取整,因为Math.random()
生成的数字是带很多位的小数所有这里取整,向下取整或向上取整都无所谓,反正是生成随机数嘛。
随机颜色生成
接下来,我们需要生成随机颜色。我们定义了randomColor()
函数,它也接受最小值和最大值作为参数,并返回一个随机的RGB颜色字符串,用于后面随机生成验证码的背景颜色。
function randomColor(min, max) {
const r = randomNum(min, max);
const g = randomNum(min, max);
const b = randomNum(min, max);
return `rgb(${r},${g},${b})`;
}
解释:在这个函数中,我们分别生成红色、绿色和蓝色的随机值(即r、g、b),并将它们组合成一个RGB颜色字符串。
绘制验证码
现在我们来编写draw()
函数,它将执行以下操作:
- 填充背景颜色。
- 在随机位置和角度上绘制随机字符。
- 绘制干扰线条。
- 绘制干扰点。
获取画布和上下文
首先,我们需要获取canvas
元素,并获取其2D绘图上下文,这样我们就可以开始在画布上绘制了。
let canvas = document.getElementById('canvas');
let ctx = canvas.getContext('2d');
解释:getContext('2d')
方法返回一个CanvasRenderingContext2D
对象,我们可以使用它来在画布上绘制。
背景颜色
我们首先设置一个随机的颜色作为背景色,并用该颜色填充整个画布。
ctx.fillStyle = randomColor(180, 230); // 设置填充颜色
ctx.fillRect(0, 0, canvas.width, canvas.height); // 用颜色填充整个画布
解释:fillStyle
属性用于设置填充图形的颜色。fillRect(x, y, w, h)
方法用于绘制一个填充矩形。
效果如下:
字符绘制
接着,我们生成四个随机字符,并在每个字符上应用随机的字体大小、旋转角度和颜色。
const pool = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'; // 验证码的字符
for (let i = 0; i < 4; i++) {
const text = pool[randomNum(0, pool.length)]; // 随机选择一个字符
const fontSize = randomNum(18, 40); // 随机字体大小
const deg = randomNum(-30, 30); // 随机旋转角度
ctx.font = `${fontSize}px SimHei`; // 设置字体和大小
ctx.textBaseline = 'top'; // 文本基线设为顶部
ctx.fillStyle = randomColor(80, 150); // 设置填充颜色
ctx.save(); // 保存当前状态
ctx.translate(30 * i + 15, 15); // 移动坐标原点
ctx.rotate((deg * Math.PI) / 180); // 旋转画布
ctx.fillText(text, -10, -15); // 绘制文本
ctx.restore(); // 恢复之前的状态
}
解释:
font
:用于设置文本的字体和大小。textBaseline
:用于设置文本基线的位置,使验证码的字母的头部对齐。fillText(text, x, y)
:用于在指定位置绘制文本。save()
:当前状态封存入栈。translate(x, y)
:把字母平移到相对的位置。rotate()
:将字母旋转,现实中我们看到的字母都是歪七扭八的对吧。restore()
:恢复出栈,可以继续画别的东西。
效果如下:
干扰线条
为了增加复杂度,我们绘制一些随机的线条,这些线条也将具有随机的颜色。
for (let i = 0; i < 5; 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(); // 绘制线条
}
解释:
beginPath()
:开始一个新的路径。moveTo(x, y)
:将绘制起点移动到指定位置。lineTo(x, y)
:用于从当前位置画一条直线到指定位置。strokeStyle
:用于设置描边的颜色。closePath()
:用于关闭当前路径,不然下一条线就会从上一条线开始。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, 200); // 设置填充颜色
ctx.closePath(); // 闭合路径
ctx.fill(); // 填充圆形
}
解释:
arc(x, y, radius, startAngle, endAngle)
:用于绘制一个弧线,我们这里把画一个小圆形再填充一下就是小圆点了对吧。fill()
方法用于填充当前路径,变成一个实现有颜色的圆。
效果如下:
完整代码奉上
将所有这些放在一起,完整的代码如下:
<!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>
<script>
let pool='ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'
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})`
}
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)
//随机生成字符串
for(let i=0;i<4;i++){
const text=pool[randomNum(0,pool.length)]
//随机字体大小
const fontSize=randomNum(18,40)
//随机旋转角度
const deg=randomNum(-30,30)
ctx.font=`${fontSize}px SimHei`
ctx.textBaseline='top'
ctx.fillStyle=randomColor(80,150)
ctx.save() //当前状态封存入栈
ctx.translate(30*i+15,15)
ctx.rotate((deg*Math.PI)/180)
ctx.fillText(text,-10,-15)
ctx.restore() //恢复出栈,可以继续画别的东西
}
//随机生成干扰线条
for(let i=0;i<5;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) //(x,y(圆心),半径,起始弧度,旋转角度)
ctx.fillStyle=randomColor(150,200)
ctx.closePath()
ctx.fill()
}
}
draw()
</script>
</body>
</html>
总结
通过上述步骤,我们成功地创建了一个简单的图形验证码生成器。您可以进一步优化和扩展此代码,实现一个更好的验证码。
文章到这里就结束了,希望对你有所帮助,感谢你的阅读!