手工编写一个验证码功能组件
0 写在前面
校历第7周,又到了周末,总得来讲这周还算不错,有一些自己的时间去学习自己喜欢的东西。不过软工项目就要开始做了,还是要予以重视的。在我室友的软工项目里,用到了一个注册验证的验证码,我看了看他在网上找的实现方法,感觉效果不太好,所以我决定亲自动手帮他实现一个!
在这个验证码功能的实现过程中,我主要练习了以下几个知识点:
-
canvas绘图功能
-
JQuery的简单用法
-
JS鼠标响应
-
以及其他CSS的布局与调整等等
感兴趣的朋友可以点击博客右上角的小猫咪进入我的github,或点击这里下载源代码。
1 实现效果与需求分析
1-1 初始效果
需要随机生成验证码图片,设置刷新与提交按钮,隐藏错误提示信息。
1-2 正确性验证
需要对用户输入与验证码内容进行匹配验证。
若输入正确,则提示正确,若有与后端交互,则可以向后端发送验证成功信息。在这里我采用的实现为自动刷新验证码,如有需求可恨容易地进行替换。
若输入错误,则需根据错误类型(如不匹配或输入为空等),进行相应的错误提示。
1-3 其他功能
在用户重新输入鼠标聚焦于输入框时,需要自动隐藏上述错误提示信息。
此外,还应实现用户点击刷新按钮即可更换验证码的功能。
2 实现细节
2-1 初始化验证码文档结构
在HTML部分,我们的实现比较简单,将整体上划分为4个部分:输入框、错误提示、验证码画布以及提交按钮。
这里面用到的DOM包括input、span、button和canvas。
这里canvas是今天练习中的重点。
代码如下:
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 <meta http-equiv="X-UA-Compatible" content="ie=edge"> 7 <title>Verification Code</title> 8 <link rel="stylesheet" href="demo.css"> 9 </head> 10 <body> 11 <div class="wrapper"> 12 <div class="inputBox"> 13 <input type="text" class="inp"> 14 <span class="icon"></span> 15 </div> 16 <p class="errorText">Wrong verification code!<br>Please check and input again!</p> 17 <div class="box"> 18 <canvas id="myCanvas" width="270" height="80"></canvas> 19 <input type="button" class="refresh"> 20 </div> 21 <button class="submit">submit</button> 22 </div> 23 24 <script src="jquery.js"></script> 25 <script src="demo.js"></script> 26 </body> 27 </html>
2-2 初始化样式
在样式的初始化中,还是练习到了基本的CSS布局操作。
这里主要有两个需要复习的地方:
-
box-sizing:border-box; 这个属性用来调整盒模型为IE盒模型。IE与W3C盒模型的区别在于对width的定义,IE盒模型中width包含了content+padding+border。因此我们常用这个属性使得盒模型的宽度更容易定义与控制。
-
position:relative; 关于定位,我们为了让子元素能使用absolute相对于其最近的有定位的父元素进行定位。因此,我们可以为要进行绝对定位的子元素最近的父元素设置一个position:relative;使子元素能够相对其进行定位。
外层样式如下:
1 *{ 2 margin: 0; 3 padding: 0; 4 } 5 .wrapper{ 6 margin: 50px auto; 7 padding: 20px; 8 width: 350px; 9 border: 1px solid #ccc; 10 border-radius: 15px; 11 box-sizing: border-box; 12 position: relative; 13 }
输入框样式如下:
这里我们对默认的输入框通过增加border-radius圆角,和padding内边距来进行美化。此外还可以去除掉input默认的外边框outline:none;
1 .inputBox{ 2 position: relative; /*absolute定位相对于有定位的最近的父元素*/ 3 } 4 .inputBox .inp{ 5 display: inline-block; 6 width: 270px; 7 border: 1px solid #ccc; 8 border-radius: 5px; 9 box-sizing: border-box; /*调整为IE盒模型,将border与padding计算入width内*/ 10 padding: 10px; 11 margin: 10px 0; 12 outline: none; 13 } 14 .inputBox .icon{ 15 display: none; 16 /* display: inline-block; */ 17 height: 32px; 18 width: 32px; 19 background: url(images/true.png); 20 background-size: 100%; 21 position: absolute; 22 top: 50%; 23 right: 0; 24 margin-top: -16px; 25 }
错误提示信息如下:
在初始时需要隐藏,且不占位,因此需要用display:none;而不能用visibility或opacity来进行设置。
1 .errorText{ 2 display: none; 3 /* display: inline-block; */ 4 color: red; 5 font-size: 14px; 6 margin-left: -10px; 7 text-align: center; 8 margin-bottom: 10px; 9 }
画布和刷新按钮的设置如下:
1 canvas{ 2 border: 1px solid #000; 3 border-radius: 5px; 4 background: url(images/bg.jpg); 5 box-sizing: border-box; 6 } 7 .box{ 8 position: relative; 9 } 10 .refresh{ 11 width: 32px; 12 height: 32px; 13 background: url(images/update.png); 14 background-size: 100%; 15 border: 0; 16 border-radius: 5px; 17 position: absolute; 18 top: 50%; 19 margin-top: -16px; 20 right: 0; 21 outline: none; 22 cursor: pointer; 23 }
最后是提交按钮的设计,让button变得更好看:
1 .submit{ 2 color: #fff; 3 padding: 10px 20px; 4 border: 0; 5 border-radius: 5px; 6 background-color: #62b900; 7 font-size: 16px; 8 outline: none; 9 cursor: pointer; 10 margin-top: 15px; 11 }
2-3 生成验证码
到这里我们已经搭好了验证码组件的框架,现在就可以为它填充内容并绑定响应事件了!
在生成验证码的阶段,我们需要用到一个数组去存储验证码的“仓库”,从这个“仓库”中随机取指定长度位数的验证码进行组合拼接,生成我们的验证码。
这里有以下几点需要说明:
-
arr.push(val); 实现了想数组尾部压入新的值val
-
String.fromCharCode(i); 实现了int->char
-
window.onload = function(){}; 提供主函数入口init()
1 var arr=[0,1,2,3,4,5,6,7,8,9]; //存放数和字符作为随机库 2 var canvasStr , valueRight ; //生成的验证码序列字符串 3 var VCLEN = 6; //验证码长度 4 var myCanvas; //画布 5 var ctx; //画笔 6 7 function init(){ 8 for(var i = 65 ; i < 122 ; i ++){ //生成随机库 9 if(i > 90 && i < 97){ 10 continue; 11 } 12 arr.push(String.fromCharCode(i));//向随机库中压入字符 13 } 14 createCanvas(); //绘制验证码 15 bindEvent(); //绑定鼠标点击响应 16 } 17 18 window.onload = function(){ 19 init(); //主函数入口 20 }
2-4 验证码的绘制createCanvas()
每次绘制前需要对验证码存储进行清空操作。
在JS中对dom元素进行操作需要首先获取它,JQuery中获取dom元素的方式非常简单,$(selector)即可获取到。
在canvas上绘图需要创建一个“画笔”对象ctx,它由getContext('2d')生成,表示在2d空间内进行绘制。
1 function createCanvas(){ 2 var len = arr.length; 3 canvasStr = ''; //每次绘制前必须清空验证码串 4 valueRight = ''; 5 for(var i = 0 ; i < VCLEN ; i ++){ //生成验证码 6 var text = arr[Math.floor(Math.random() * len)]; 7 canvasStr += (text + " "); //画布上的验证码之间有空格 8 valueRight += text; 9 } 10 11 myCanvas = $('#myCanvas')[0]; //从html中获取Canvas元素 12 ctx = myCanvas.getContext('2d'); //创建二维画笔,方法返回一个用于在画布上绘图的环境 13 14 drawLine(); //绘制干扰用线条 15 fillVerificationCode(); //绘制验证码字符 16 }
画线函数:
这里需要注意的是,在每次绘制函数被调用前,应该先清空一次画布区域,我们采用的是clearRect(x1,y1,x2,y2)。这个方法可以清除指定的矩形区域,参数为坐标点的形式给出。
随机数写法:Math.floor(Math.random() * n)
1 function drawLine(){ 2 ctx.beginPath(); //开始绘制 3 ctx.clearRect(0,0,myCanvas.width,myCanvas.height); //清空画布区域,坐标点(x1,y1,x2,y2) 4 ctx.lineWidth = 15; //规定宽度 5 ctx.strokeStyle = '#ccc'; //规定线条颜色 6 ctx.moveTo(Math.floor(Math.random()*30) , Math.floor(Math.random()*80)); //规定起点 7 ctx.lineTo(250+Math.floor(Math.random()*20) , Math.floor(Math.random()*80)); //规定终点 8 ctx.stroke(); //绘制 9 ctx.globalCompositeOperation = 'lighter'; //源图像与目标图像叠加显示 10 ctx.closePath(); //结束绘制 11 }
绘制验证码函数:
由于验证码在绘制时涉及到旋转操作,需要注意的是在绘图过程中若要有进行平移、放缩、旋转、错切、裁剪等操作,必须在前后增加save()和restore()来进行锁控制。否则会在每次刷新时,出现意想不到的未被清除的毛边。
1 function fillVerificationCode(){ 2 //若要进行平移、放缩、旋转、错切、裁剪等操作,需再其前后增加save()和restore()。 3 ctx.save(); 4 ctx.beginPath(); 5 var x = myCanvas.width / 2; 6 ctx.textAlign = 'center'; 7 ctx.fillStyle = '#ddd'; 8 ctx.font = '46px Roboto Slab'; 9 ctx.setTransform(1 , -0.12 , 0.2 , 1 , 0 , 12); //将文字设置倾斜效果 10 ctx.fillText(canvasStr , x , 60); //参数:内容,开始点坐标x,y 11 ctx.restore(); 12 }
2-5 对用户输入的验证与刷新
好了,现在我们已经绘制成功了验证码,接下来就需要编写验证逻辑和增加鼠标响应了。
大致思路就是为submit、refresh和input的聚焦绑定一个鼠标点击事件的监听,每当触发时就进行响应。
如果点击了refresh,则调用一下上面编写过的createCanvas()重新生成一个验证码,并隐藏掉错误提示。
如果是input的聚焦,则隐藏错误提示。
如果点击了submit,则进行多步判断:是否为空、是否匹配,并根据判断结果做出具体响应。
这里主要练习到了JQuery的以下几个要点:
-
val(): 取得输入的值,通常与input搭配使用
-
trim(): 可以过滤掉string前后的空白(包括空格和tab)
-
show(): 可以取消display:none的效果
-
html(): 相当于InnerHTML
-
css(): 可以编辑选中元素的CSS样式,注意属性值用' '来包含
-
add(): 添加一个新元素到JQuery对象
-
fadeOut(time): 淡出(消失)
1 function bindEvent(){ 2 //为提交绑定鼠标点击事件 3 $('.submit').on('click',function(){ 4 //获取输入 5 var value = $('.inp').val().trim(); //trim()会去掉内容前后的空白 6 //先判断是否输入为空 7 if(value == '' || value == null || value == undefined){ 8 // show()可以取消display:none html(text)可以改变html里的内容 9 $('.errorText').show().html('Please input context.'); 10 // css()可以修改选中元素的样式,用','分割,内容需要用''包含。 11 $('.icon').css({ 12 display: 'inline-block', 13 backgroundImage: 'url("images/false.png")' 14 }); 15 } 16 else{ 17 // 判断是否与目标相一致 18 if(value == valueRight){ 19 $('.icon').css({ 20 display: 'inline-block', 21 backgroundImage: 'url("images/true.png")' 22 }); 23 createCanvas(); //可以用向后端反馈验证成功信息代替之 24 } 25 else{ 26 $('.errorText').show().html('Wrong verification code!<br>Please check and input again!.'); 27 $('.icon').css({ 28 display: 'inline-block', 29 backgroundImage: 'url("images/false.png")' 30 }); 31 } 32 } 33 }) 34 //为刷新按钮添加鼠标点击事件 35 $('.refresh').on('click',function(){ 36 createCanvas(); 37 //add()用于添加一个元素到jQuery对象。fadeOut()淡出(逐渐消失) 38 $('.errorText').add('.icon').fadeOut(100); 39 }); 40 //错误提示后鼠标再次聚焦消除错误提示 41 $('.inp').focus(function(){ 42 $('.errorText').add('.icon').fadeOut(100); 43 }); 44 }
3 总结
通过编写验证码功能组件的练习,我主要复习了canvas绘图的一些基本操作,JQuery的一些简单方法的组合使用,以及JS鼠标事件的响应机制。
这样,我的室友就可以用一个更漂亮的验证码界面组件来完善他的软工项目啦!很荣幸我的工作对他的团队完成项目能有帮助~~
明天要去冯如杯6审答辩,后天英语竞赛和程序设计大赛~祝自己好运吧!