JS实现一个简易图片验证码

3,927 阅读2分钟

这是我参与更文挑战的第1天,活动详情查看:更文挑战

JS可以利用Canvas元素设计一些简单的图形,今天利用Canvas元素实现一个简易的图片验证码。设计过程和效果如下,不正之处,敬请指正。 验证码.gif (本文侧重于js,界面简陋,还望见谅)

总体思路

  1. 编写随机数生成函数和随机颜色生成函数
  2. 获取Canvas2d上下文
  3. 设计验证码生成函数
    • 清除上轮验证码,设置Canvas背景
    • 生成本轮验证码
    • 随机确定每位验证码所在位置、颜色、阴影
    • 使用fill画出验证码、使用translaterotate随机确定验证码旋转角度
    • 设计干扰线和干扰带点
    • 随机确定干扰线数量、颜色、位置
    • 随机确定干扰点数量、颜色、位置
    • 将验证码生成函数通过click事件绑定在Canvas上。
  4. 设计验证函数,验证用户数据是否正确
    • 验证函数:判断是否验证成功,若成功输出成功信息,否则输出失败,并刷新验证码。
    • 将验证函数通过click绑定在确定btn中。

涉及基础知识

1.设计随机数生成函数

  • 使用Math.random生成[0,1)随机数。
  • 使用Math.floor可以将某数向下取整
//value is 1
Math.floor(1.2); 
// equal to below
Math.floor(1);

随机数生成函数如下:

/* 返回一个随机数[minNum,maxNum] */
function randomNum(minNum,maxNum){
    return Math.floor(Math.random() * (maxNum - minNum + 1)) + minNum
}

/* 返回一个随机颜色[minNum,maxNum] */
function randomColor(minNum,maxNum){
    return `rgba(${randomNum(minNum,maxNum)},${randomNum(minNum,maxNum)},${randomNum(minNum,maxNum)},0.8)`;
}

2.DOM中设置、获取style属性值

CSSStyleDeclaration 对象设置内联的style

DOM中有个HTMLElement类型,所有HTML元素都是HTMLElement或其子类型的实例。

HTMLElement类型中包含一个style属性,该属性类型为 CSSStyleDeclaration ,表示HTML元素的内联style属性<elem style="...">,但不含样式表应用属性。 CSSStyleDeclaration 是只读的,但是可以通过CSSStyleDeclaration属性设置HTML样式。例如以下三种设置style的方式:

//elt是`HTMLElement`类型的实例

// 方法一:在单个语句中设置多个样式,改变ele中所有内联样式
elt.style.cssText = "color: blue; border: 1px solid black";

// 方法二:使用HTMLElement中setAttribute方法,改变ele中所有内联样式
elt.setAttribute("style", "color:red; border: 1px solid blue;");

// 方法三:设置特定样式,同时保持其他内联样式值不变,
// 该设置等价于<elt style="background-color:blue;...">
//(本文中使用的方法)
elt.style.backgroundColor = "blue";

CSSStyleDeclaration 对象的属性命名规则为小驼峰,比如css中的background-color属性,对应DOM CSSStyleDeclaration 对象的属性backgroundColor

使用Window.getComputedStyle()获取所有style样式

Window.getComputedStyle()方法返回一个实时的 CSSStyleDeclaration 对象,当元素的样式更改时,它会自动更新本身。返回的 CSSStyleDeclaration 对象存储解析css样式表后的属性值。

//Window.getComputedStyle()使用语法,其中pseudoElt指定一个要匹配的伪元素的字符串
let style = window.getComputedStyle(element, [pseudoElt]);
//获取属性height,
let theCSSprop = window.getComputedStyle(elem,null).getPropertyValue("height");

3.Canvasfill方法簇和stroke方法簇

2d上下文的两个基本操作为填充和描边,对应Canvas元素的绘制方法为fill方法簇和stroke方法簇。

比如画个圆。使用stroke方法效果如下(描边):

image.png

使用fill方法效果如下(填充):

image.png

填充:fill方法簇

fill方法簇和stroke方法簇中的方法基本一致,绘制图片验证码中需要使用fillText方法绘制基本

  • 填充矩形fillRect方法
  • 填充文本fillText方法
  • 填充路径fill方法

fill方法簇有通用的fillStyle属性确定填充的显示效果

描边:stroke方法簇

  • 填充矩形strokeRect方法
  • 填充文本strokeText方法
  • 填充路径stroke方法

stroke方法簇有通用的strokeStyle属性确定描边的显示效果

4.Canvas的位移和旋转

2d上下文中支持常见的变换操作,变换的原点初始为(0,0)。

  • rotate(angle): 围绕原点把图形旋转angle角度。
  • translate(x,y): 将原点移动至(x,y)。

实现简易图片验证码

1.基本html框架

    <div id="v_container" style="width: 200px;height: 50px;"></div>
    <input type="text" id="code_input" value="" placeholder="请输入验证码"/><button id="my_button">验证</button>

2.绘制4位验证码

    /*绘制4位验证码*/
    for(let i=4;i>0;i--){
        /*设置验证码0-9*/
        const num = randomNum(0,codeRef.length-1); 
        
        /*设置每个验证码的x,y坐标以及旋转角度*/
        const x = (img.width / 5) * i+randomNum(-10,10);
        code = num + code;
        const y = randomNum(35,45);
        const r = randomNum(-30,30) * Math.PI / 180;
   
        /*注意顺序:先定原点,再旋转,否则出错*/
        ctx.translate(x,y);
        ctx.rotate(r);

        /*通过fillStyle设置验证码样式,通过fillText绘制验证码*/
        ctx.fillStyle = `rgba(${randomNum(10,50)},${randomNum(10,50)},${randomNum(10,50)},0.6)`;
        ctx.font = `${randomNum(30,40)}px Arial`;
        ctx.shadowOffsetX = 3;
        ctx.shadowOffsetY = 3;
        ctx.shadowBlur = 3;
        ctx.shadowColor = "rgba(0,0,0,0.5)";
        ctx.fillText(codeRef[num].toString(),0,0);
        
        /*注意:设置好1位验证码后,撤销位移和旋转设置,否则出错*/
        ctx.rotate(-1*r);
        ctx.translate(-1*x,-1*y); 
    }

3.绘制干扰线和干扰点

基本方法和绘制验证码一致

    ctx.beginPath();
    for(let i=0;i<randomNum(4,6);i++){
        /*确定干扰线起点和终点坐标*/
        startX = randomNum(0,img.width/2);
        startY = randomNum(0,img.height);

        endX = randomNum(img.width/2,img.width);
        endY = randomNum(0,img.height);
        
        /*使用stroke方法绘制干扰线*/
        ctx.strokeStyle = `rgba(${randomNum(100,130)},${randomNum(100,130)},${randomNum(100,130)},${randomNum(0.3,0.9)})`;
        ctx.moveTo(startX,startY);
        ctx.lineTo(endX,endY);
        ctx.stroke();
    }
    
    for(let i=0;i<randomNum(10,20);i++){
        /*确定干扰点坐标*/
        x = randomNum(0,img.width);
        y = randomNum(0,img.height);
            
        /*使用fill方法绘制干扰点,注意干扰点要使用填充方式*/
        ctx.fillStyle = `rgba(${randomNum(100,130)},${randomNum(100,130)},${randomNum(100,130)},${randomNum(0.3,0.9)})`;
        ctx.moveTo(x,y);
        /*通过arc方法绘制坐标为(0,0,),半径为1,起点角度为0度,终点角度为360度的圆形黑点(干扰点)*/
        ctx.arc(x,y,1,0,2*Math.PI,false);
        ctx.fill();
    }

4.绑定对应函数

图片验证码要求在页面加载时或点击图片时更新验证码,此外,需要在点击确认按钮时验证用户填入信息是否正确。

 window.onload = changeVerifyCode;
 img.addEventListener('click',changeVerifyCode);
 btn.addEventListener('click',verify);

写在最后

本文以Canvas元素为出发点,通过js实现一个简易的图片验证码,希望对你在使用Canvas绘图过程中有所启发。