使用Canvas创建动态验证码<canvas>是HTML5中新增的一个元素,这个元素本身仅仅只是一个容器,真正的绘图工作
前言
<canvas>
是HTML5中新增的一个元素,这个元素本身仅仅只是一个容器,真正的绘图工作是需要通过 JavaScript 的 Canvas API 来完成的。Canvas API 提供的一系列方法和属性使得<canvas>
非常适合于绘制动态图形、进行游戏开发、实现复杂的用户界面交互等场景。
本篇文章首先会向读者介绍一些canvas的基础知识,然后通过实操写一个验证码的demo来展示canvas的强大用法。
canvas标签基础
创建了一个HTML文件,向body中添加一个<canvas>
元素,并为其设置一个id:canvas(<canvas id="canvas"></canvas>
),以便我们可以通过JavaScript来访问它。接着,在<script>
标签内,我将编写一些JavaScript代码来绘制图形,以便更加形象地向你们介绍有关canvas的一些方法以及如何使用它们。
首先,我们通过document.getElementById
获取canvas元素,并调用其getContext("2d")
方法来获取一个2D渲染上下文(即绘图环境)。
let canvas = document.getElementById("canvas");
let ctx = canvas.getContext("2d"); // 用canvas标签创建一张2D的画布ctx
绘制矩形
-
fillRect(x, y, width, height)
:用于在给定的矩形区域内填充颜色。x 和 y 参数指定了矩形左上角的坐标,width 和 height 参数指定了矩形的宽度和高度。 -
strokeStyle
:这是一个属性,它设置了线条或者边框等的描边颜色。 -
strokeRect(x, y, width, height)
: 类似于 fillRect,但这个方法不是填充矩形,而是用于描边矩形,它同样接受矩形的左上角坐标、宽度和高度作为参数。
ctx.fillRect(0, 0, 100, 100) // 在画布上绘制一个矩形(两个坐标确定矩形的左上角和右下角)
ctx.strokeStyle = "red" // 设置描边颜色
ctx.strokeRect(0, 0, 100, 100) // 描边
绘制圆形
-
beginPath()
:在进行路径绘制之前调用此方法。它重置当前的路径,清除之前定义的所有点、线和形状,从而开始一个新的路径。 -
closePath()
:闭合当前路径。从当前点绘制一条直线到路径的起始点,从而闭合路径。closePath() 本身并不绘制任何内容到画布上,它仅仅是定义了一个闭合的路径,该路径可以通过 fill() 或 stroke() 方法来填充或描边。 -
arc(x, y, radius, startAngle, endAngle, anticlockwise)
:这个方法用于在画布上绘制一个圆或圆弧。x 和 y 定义了圆心的坐标,radius 是圆的半径,startAngle 和 endAngle 是圆弧的起始和结束角度(以弧度为单位),anticlockwise 是一个布尔值,圆弧是否应该按逆时针方向绘制,默认为false,即顺时针方向。 -
fillStyle
:用于设置填充样式的属性。 -
fill()
:使用当前的填充样式(由 fillStyle 属性设置)填充当前的闭合的路径。
ctx.beginPath() // 开始一条路径的描述
ctx.arc(150, 75, 50, 0, Math.PI * 2) // 绘制一个弧形(圆心坐标, 半径, 起始弧度, 结束弧度)
ctx.fillStyle = "blue"
ctx.fill() // 填充
绘制空心圆
-
lineWidth
:设置描边线条宽度的属性。 -
stroke()
:遍历当前路径中的所有点,并使用指定的样式来绘制这些点之间的线条。
ctx.beginPath()
ctx.arc(150, 75, 50, 0, Math.PI * 2)
ctx.strokeStyle = "blue"
ctx.lineWidth = 5 // 设置线条的宽
ctx.stroke() // 描边
创建验证码
HTML结构
在body中定义一个ID为"canvas"的<canvas>
元素。设定画布的尺寸为120x40像素,并且包含一个onclick
事件监听器,每当点击画布时都会触发draw()
函数来绘制新的验证码。
<canvas id="canvas" width="120" height="40" onclick="draw()"></canvas>
JavaScript实现
随机函数
在生成验证码之前,我们需要写一些辅助函数用于生成验证码中的随机文本、颜色、偏转角度、位置等等。因此我们定义了两个函数:randomNum
用于生成给定范围内的随机数。randomColor
根据给定的最小和最大亮度值生成随机 RGB 颜色。
let pool = "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
// 随机数
function randomNum(min,max){
// Math.random() 0-1
// Math.floor() 向下取整
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})`
}
绘制验证码
在 draw
函数中,我们利用 Canvas 2D 上下文来绘制验证码。首先,使用随机颜色来填充画布背景,然后循环生成随机字符,再次使用随机函数来设置字体大小、旋转角度等样式。
其中重点介绍一下save
和 restore
方法,它们分别用于保存和恢复当前的绘图状态,这样在绘制下一个字符时不会受到前一个字符的变换(如平移和旋转)的影响。
// 绘制一个验证码
function draw(){
let canvas = document.getElementById("canvas");
let ctx = canvas.getContext
// 随机填充色
ctx.fillStyle = randomColor(180,230)
ctx.fillRect(0, 0, canvas.width, canvas.
let imgCode = ''
// 随机生成字符串
for(let i = 0; i < 4; i++){
const text = pool[randomNum(0, pool.length)]
imgCode += text
// 随机字体大小
const fontSize = randomNum(18, 40)
// 随机旋转角度
const deg = randomNum(-30, 30)
// 绘制文字样式
ctx.font = `${fontSize}px SimHei`
ctx.textBaseline = 'top' // 文字垂直对齐方式
ctx.fillStyle = randomColor(80, 160)
ctx.save() // 将当前状态封存入栈
ctx.translate(i * 30 + 15, 15)
ctx.rotate((deg * Math.PI) / 180)
ctx.fillText(text, -10, -15)
ctx.restore() // 出栈
}
}
draw()
添加图形干扰
为了提高验证码的安全性,我们需要添加一些图形干扰,如随机线条和圆点,这些干扰项能够增加机器识别验证码的难度。
// 随机生成干扰线
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, Math.PI * 2)
ctx.fillStyle = randomColor(100, 230)
ctx.closePath()
ctx.fill()
}
总结
通过上述步骤,我们成功创建了一个包含随机字符、随机样式以及图形干扰的验证码,用户可以通过点击画布刷新验证码,提高了用户体验。通过本文的介绍,相信你已经对<canvas>
元素有了初步的认识,并感受到了它强大的绘图能力。但要知道,这只是Canvas的冰山一角,在不断深入学习canvas后你将能够开发出更加丰富、动态和吸引人的网页内容,为用户带来前所未有的体验。
转载自:https://juejin.cn/post/7389069052437020712