Canvas入门实战之实现一个图形验证码

开发 前端
本文主要介绍用canvas实现图形验证码的一些思路以及如何用javascript面向对象的方式更友好的实现canvas的功能,关于canvas的一些基本使用方法和API我整理了一个思维导图,大家感兴趣的可以参考学习。

[[358782]]

 本文主要介绍用canvas实现图形验证码的一些思路以及如何用javascript面向对象的方式更友好的实现canvas的功能,关于canvas的一些基本使用方法和API我整理了一个思维导图,大家感兴趣的可以参考学习。 

 

你将收获

  • 闭包的使用
  • canvas常用api的使用
  • javascript面向对象的实现方式
  • 实现一个canvas的图形验证码的一般思路和常用算法

设计思路

  1. 用canvas生成画布
  2. 用canvas画干扰线或躁点
  3. 生成随机不重复的n的字母
  4. 用canvas绘制文字
  5. 初始化和canvas点击事件
  6. 组件化封装

文末将附上组件封装的源码,欢迎大家随时沟通交流。关于项目的打包,我将使用自己基于gulp4搭建的9012教你如何使用gulp4开发项目脚手架。

效果预览

图片

实现思路

我将按照上文中的设计思路的步骤一步步实现,首先我们先定义一个es5类:

  1. function Gcode(el, option) { 
  2.     this.el = typeof el === 'string' ? document.querySelector(el) : el; 
  3.     this.option = option
  4.     this.init(); 

其中init是用来初始化用的,参数el代表需要挂载的元素或元素id,option为传入的可选项,稍后会在代码中体现,通常这也是面向对象的常用套路。

1.绘制画布

  1. Gcode.prototype = { 
  2.     constructor: Gcode, 
  3.     init: function() { 
  4.         if(this.el.getContext) { 
  5.             isSupportCanvas = true
  6.             var ctx = this.el.getContext('2d'), 
  7.             // 设置画布宽高 
  8.             cw = this.el.width = this.option.width || 200, 
  9.             ch = this.el.height = this.option.height || 40; 
  10.         } 
  11.     } 

这里我们在初始化方法中先定义一个canvas画布,宽高为用户自定义的宽高,默认为200*40。

2.绘制干扰线

  1. // 画干扰线 
  2. drawLine: function(ctx, lineNum, maxW, maxH) { 
  3.     ctx.clearRect(0, 0, maxW, maxH); 
  4.     for(var i=0; i < lineNum; i++) { 
  5.         var dx1 = Math.random()* maxW, 
  6.             dy1 = Math.random()* maxH, 
  7.             dx2 = Math.random()* maxW, 
  8.             dy2 = Math.random()* maxH; 
  9.         ctx.strokeStyle = 'rgb(' + 255*Math.random() + ',' + 255*Math.random() + ',' + 255*Math.random() + ')'
  10.         ctx.beginPath(); 
  11.         ctx.moveTo(dx1, dy1); 
  12.         ctx.lineTo(dx2, dy2); 
  13.         ctx.stroke(); 
  14.     } 

这里我们对类Gcode定义原型方法drawLine,然后通过for循环绘制随机位置的线条,为了让canvas每次点击能清空之前的干扰线,我们使用clearRect来清除画布。

3.生成随机不重复的n个字符

我们通过递归实现,如下==:

  1. // 生成唯一文字 
  2. generateUniqueText: function(source, hasList, limit) { 
  3.     var text = source[Math.floor(Math.random()*limit)]; 
  4.     if(hasList.indexOf(text) > -1) { 
  5.         return this.generateUniqueText(source, hasList, limit) 
  6.     }else { 
  7.         return text 
  8.     }   
  9. // 生成指定个数的随机文字 
  10. randomText: function(len) { 
  11.     var source = ['a''b''c''d''e'
  12.     'f''g''h''i''j',  
  13.     'k''l''m''o''p'
  14.     'q''r''s''t''u'
  15.     'v''w''x''y''z']; 
  16.     var result = []; 
  17.     var sourceLen = source.length; 
  18.     for(var i=0; i< len; i++) { 
  19.         var text = this.generateUniqueText(source, result, sourceLen); 
  20.         result.push(text) 
  21.     } 
  22.     return result.join(''

我们通过定义一个字母表,传入生成的随机字母的个数,配合generateUniqueText来实现生成唯一不重复的n个随机字符。当然笔者认为这个方法并不优雅,你也可以使用uuid的方式或者更好的方式,欢迎随时和笔者交流。

4.用canvas绘制文字

  1. // 画文字 
  2. drawText: function(ctx, text, maxH) { 
  3.     var len = text.length; 
  4.     for(var i=0; i < len; i++) { 
  5.         var dx = 30 * Math.random() + 30* i, 
  6.             dy = Math.random()* 5 + maxH/2; 
  7.         ctx.fillStyle = 'rgb(' + 255*Math.random() + ',' + 255*Math.random() + ',' + 255*Math.random() + ')'
  8.         ctx.font = '30px Helvetica'
  9.         ctx.textBaseline = 'middle'
  10.         ctx.fillText(text[i], dx, dy); 
  11.     } 
  12. }, 

这里和上文画线实现类似。就不做过多介绍了。

5.初始化和canvas点击事件

接下来我们看看完整的初始化代码:

  1. init: function() { 
  2.     if(this.el.getContext) { 
  3.         isSupportCanvas = true
  4.         var ctx = this.el.getContext('2d'), 
  5.         // 设置画布宽高 
  6.         cw = this.el.width = this.option.width || 200, 
  7.         ch = this.el.height = this.option.height || 40, 
  8.         textLen = this.option.textLen || 4, 
  9.         lineNum = this.option.lineNum || 4; 
  10.         var text = this.randomText(textLen); 
  11.  
  12.         this.onClick(ctx, textLen, lineNum, cw, ch); 
  13.         this.drawLine(ctx, lineNum, cw, ch); 
  14.         this.drawText(ctx, text, ch); 
  15.     } 

点击事件主要是为了用户点击可以切换验证码:

  1. onClick: function(ctx, textLen, lineNum, cw, ch) { 
  2.     var _ = this; 
  3.     this.el.addEventListener('click'function(){ 
  4.         text = _.randomText(textLen); 
  5.         _.drawLine(ctx, lineNum, cw, ch); 
  6.         _.drawText(ctx, text, ch); 
  7.     }, false

到此,一个完整的验证码组件实现完成,怎么用呢?如下:

  1. new Gcode('#canvas_code', { 
  2.         lineNum: 6,  // 可选 
  3.         textLen: 4,  // 可选 
  4.         width: 200,  // 可选 
  5.         height: 50   // 可选 
  6.     }) 

完整代码如下,欢迎学习交流:

  1. // canvas绘制图形验证码 
  2.     (function(){ 
  3.         function Gcode(el, option) { 
  4.             this.el = typeof el === 'string' ? document.querySelector(el) : el; 
  5.             this.option = option
  6.             this.init(); 
  7.         } 
  8.         Gcode.prototype = { 
  9.             constructor: Gcode, 
  10.             init: function() { 
  11.                 if(this.el.getContext) { 
  12.                     isSupportCanvas = true
  13.                     var ctx = this.el.getContext('2d'), 
  14.                     // 设置画布宽高 
  15.                     cw = this.el.width = this.option.width || 200, 
  16.                     ch = this.el.height = this.option.height || 40, 
  17.                     textLen = this.option.textLen || 4, 
  18.                     lineNum = this.option.lineNum || 4; 
  19.                     var text = this.randomText(textLen); 
  20.          
  21.                     this.onClick(ctx, textLen, lineNum, cw, ch); 
  22.                     this.drawLine(ctx, lineNum, cw, ch); 
  23.                     this.drawText(ctx, text, ch); 
  24.                 } 
  25.             }, 
  26.             onClick: function(ctx, textLen, lineNum, cw, ch) { 
  27.                 var _ = this; 
  28.                 this.el.addEventListener('click'function(){ 
  29.                     text = _.randomText(textLen); 
  30.                     _.drawLine(ctx, lineNum, cw, ch); 
  31.                     _.drawText(ctx, text, ch); 
  32.                 }, false
  33.             }, 
  34.             // 画干扰线 
  35.             drawLine: function(ctx, lineNum, maxW, maxH) { 
  36.                 ctx.clearRect(0, 0, maxW, maxH); 
  37.                 for(var i=0; i < lineNum; i++) { 
  38.                     var dx1 = Math.random()* maxW, 
  39.                         dy1 = Math.random()* maxH, 
  40.                         dx2 = Math.random()* maxW, 
  41.                         dy2 = Math.random()* maxH; 
  42.                     ctx.strokeStyle = 'rgb(' + 255*Math.random() + ',' + 255*Math.random() + ',' + 255*Math.random() + ')'
  43.                     ctx.beginPath(); 
  44.                     ctx.moveTo(dx1, dy1); 
  45.                     ctx.lineTo(dx2, dy2); 
  46.                     ctx.stroke(); 
  47.                 } 
  48.             }, 
  49.             // 画文字 
  50.             drawText: function(ctx, text, maxH) { 
  51.                 var len = text.length; 
  52.                 for(var i=0; i < len; i++) { 
  53.                     var dx = 30 * Math.random() + 30* i, 
  54.                         dy = Math.random()* 5 + maxH/2; 
  55.                     ctx.fillStyle = 'rgb(' + 255*Math.random() + ',' + 255*Math.random() + ',' + 255*Math.random() + ')'
  56.                     ctx.font = '30px Helvetica'
  57.                     ctx.textBaseline = 'middle'
  58.                     ctx.fillText(text[i], dx, dy); 
  59.                 } 
  60.             }, 
  61.             // 生成指定个数的随机文字 
  62.             randomText: function(len) { 
  63.                 var source = ['a''b''c''d''e'
  64.                 'f''g''h''i''j',  
  65.                 'k''l''m''o''p'
  66.                 'q''r''s''t''u'
  67.                 'v''w''x''y''z']; 
  68.                 var result = []; 
  69.                 var sourceLen = source.length; 
  70.                 for(var i=0; i< len; i++) { 
  71.                     var text = this.generateUniqueText(source, result, sourceLen); 
  72.                     result.push(text) 
  73.                 } 
  74.                 return result.join(''
  75.             }, 
  76.             // 生成唯一文字 
  77.             generateUniqueText: function(source, hasList, limit) { 
  78.                 var text = source[Math.floor(Math.random()*limit)]; 
  79.                 if(hasList.indexOf(text) > -1) { 
  80.                     return this.generateUniqueText(source, hasList, limit) 
  81.                 }else { 
  82.                     return text 
  83.                 }   
  84.             } 
  85.         } 
  86.         new Gcode('#canvas_code', { 
  87.             lineNum: 6 
  88.         }) 
  89.     })(); 

 

责任编辑:姜华 来源: 趣谈前端
相关推荐

2009-11-23 16:59:23

PHP图形验证码

2020-01-06 13:11:30

技术工具

2021-08-11 06:57:17

验证码图片显示

2015-09-21 15:31:05

php实现验证码

2023-09-22 11:51:13

PythonFlask

2015-12-11 09:54:47

2009-12-16 15:46:41

Ruby on rai

2013-06-19 10:19:59

2018-09-18 10:11:21

前端vue.jsjavascript

2020-09-29 06:43:12

Java

2009-06-26 15:17:27

jQuery

2020-11-16 07:28:53

验证码

2009-08-11 14:05:28

JSP验证码

2009-02-09 14:17:36

2017-12-21 07:38:19

2021-01-19 10:29:34

短信验证码密码

2015-03-23 17:58:04

验证码倒计时并行

2022-02-11 07:10:15

验证码

2022-02-02 20:21:24

短信验证码登录
点赞
收藏

51CTO技术栈公众号