天天看點

手工編寫一個驗證碼功能元件

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審答辯,後天英語競賽和程式設計大賽~祝自己好運吧!