前言
前端经常在登录页面等表单组件,需要添加验证码来防止爬虫、暴力破解等恶性操作。通常验证码是通过接口去访问后台,后台创建并返回图片链接,我们再将表单内容和验证码值传给后台,后台进行验证。
但是在前端是否有方式来生成验证码并验证呢?我们可以借助canvas,具体代码如下:
1. 随机取数函数
先写一个随机取数函数,来生成验证码
传参:{number} size 获取数量
返回: {number[]} strList 随机字符列表
function genRandomStr(size = 4) {
const range = [
"0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z",
];
const strList = [];
for (let i = 0; i < size; i++) {
const randomStr = range[Math.floor(Math.random() * range.length)];
strList.push(randomStr);
}
return strList;
}
2. 生成验证码图片函数
先看个效果图:
说说思路:canvas的fillText可以填充文字,其他都是样式来做。文字填充一个后就换样式。
已经实现:随机的文字大小、随机的文字旋转、每个字符在规定区域、字符不重叠
可以拓展:随机线条(line)、随机点阵(line)、随机颜色(fillStyle)、随机放缩(transfrom)
问题:不同的长宽比,旋转的幅度需要调整,不然会跑到图外,下面修正。
function useCaptcha(width = 100, height = 50) {
// 生成随机内容
const canvas = document.createElement("canvas");
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext("2d");
const captcha = genRandomStr();
for (let i in captcha) {
const str = captcha[i];
const transLen = (width * 0.8) / captcha.length; // 偏移量
const sizeRatio = 0.3 + 0.3 * Math.random(); // 随机文字大小比例
const degRatio = (Math.random() - 0.5) * 0.5; // 随机旋转比例
ctx.font = height * sizeRatio + "px serif"; // 设置字体大小
ctx.rotate(degRatio); // 旋转
ctx.fillText(str, width * 0.1, height * 0.8, width * 0.8); // 填充文字
ctx.translate(transLen, 0); // 偏移
ctx.rotate(-degRatio); // 恢复旋转
}
const result = {
imgSrc: canvas.toDataURL(),
value: captcha.join(""),
};
return result;
}
3. 拓展
效果图:
如何?是不是有那么点意思了,具体代码如下:
颜色拓展:
颜色直接随机,也可以自定义一个好看的颜色区间随机,也可以用rgba带点透明效果。
function randomColor() {
const randR = Math.floor(Math.random() * 256);
const randG = Math.floor(Math.random() * 256);
const randB = Math.floor(Math.random() * 256);
return `rgb(${randR},${randG},${randB})`;
}
线条拓展:
我们通过迭代的方式,画了50条直线。
1. 先将translate归位
2. 新建画图路径,不然就是一条线了
function useCaptcha(width = 100, height = 50) {
// 生成随机内容
const canvas = document.createElement("canvas");
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext("2d");
const captcha = genRandomStr();
for (let i in captcha) {
const str = captcha[i];
const transLen = (width * 0.8) / captcha.length;
const sizeRatio = 0.3 + 0.3 * Math.random();
const degRatio = (Math.random() - 0.5) * (width / height); // 用长宽比就没事了
ctx.font = height * sizeRatio + "px serif";
ctx.rotate(degRatio);
ctx.fillStyle = randomColor(); // ---新增
ctx.fillText(str, width * 0.1, height * 0.8, width * 0.8);
ctx.translate(transLen, 0); // 偏移
ctx.rotate(-degRatio); // 恢复旋转
}
ctx.translate(-width * 0.8, 0); // ---新增
for (var i = 0; i <= 50; i++) {
ctx.beginPath(); // 新建画图路径
ctx.strokeStyle = randomColor();
ctx.moveTo(Math.random() * width, Math.random() * height);
ctx.lineTo(Math.random() * width, Math.random() * height);
ctx.stroke();
}
const result = {
imgSrc: canvas.toDataURL(),
value: captcha.join(""),
};
return result;
}
完整代码
在网页中显示,完整代码如下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<style>
#captcha {
width: 300px;
height: 150px;
}
</style>
<body>
<img id="captcha" src="" />
<script>
/**
* @param {number} size 随机字符数
* @return {str[]} 验证码列表
*/
function genRandomStr(size = 4) {
const range = [
"0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z",
];
const strList = [];
for (let i = 0; i < size; i++) {
const randomStr = range[Math.floor(Math.random() * range.length)];
strList.push(randomStr);
}
return strList;
}
/**
* @param {number} width 验证码高度
* @param {number} height 验证码宽度
* @return {imgSrc:string,value:string} 返回图片链接,验证码值
*/
function useCaptcha(width = 100, height = 50) {
// 生成随机内容
const canvas = document.createElement("canvas");
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext("2d");
const captcha = genRandomStr();
for (let i in captcha) {
const str = captcha[i];
const transLen = (width * 0.8) / captcha.length;
const sizeRatio = 0.3 + 0.3 * Math.random();
const degRatio = (Math.random() - 0.5) * (width / height); // 设置为长宽比不会旋转太过
ctx.font = height * sizeRatio + "px serif";
ctx.rotate(degRatio);
ctx.fillStyle = randomColor();
ctx.fillText(str, width * 0.1, height * 0.8, width * 0.8);
ctx.translate(transLen, 0); // 偏移
ctx.rotate(-degRatio); // 恢复旋转
}
ctx.translate(-width * 0.8, 0);
for (var i = 0; i <= 50; i++) {
ctx.beginPath(); // 新建画图路径
ctx.strokeStyle = randomColor();
ctx.moveTo(Math.random() * width, Math.random() * height);
ctx.lineTo(Math.random() * width, Math.random() * height);
ctx.stroke();
}
const result = {
imgSrc: canvas.toDataURL(),
value: captcha.join(""),
};
return result;
}
function setImg() {
const imgDom = document.getElementById("captcha");
const captchaObj = useCaptcha(300, 150);
imgDom.src = captchaObj.imgSrc;
console.log("验证码值:", captchaObj.value);
}
function randomColor() {
const randR = Math.floor(Math.random() * 256);
const randG = Math.floor(Math.random() * 256);
const randB = Math.floor(Math.random() * 256);
return `rgb(${randR},${randG},${randB})`;
}
setImg();
</script>
</body>
</html>
好了,就拓展到这里了,有什么问题大家可以一起探讨~
路过的可以点个收藏,万一用上了呢😊