当前位置:首页 > 数据库

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

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

你将收获

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

设计思路

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

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

效果预览

实现思路

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

function Gcode(el,入门 option) {      this.el = typeof el === string ? document.querySelector(el) : el;     this.option = option;     this.init(); } 

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

1.绘制画布

Gcode.prototype = {      constructor: Gcode,实战     init: function() {          if(this.el.getContext) {              isSupportCanvas = true;             var ctx = this.el.getContext(2d),             // 设置画布宽高             cw = this.el.width = this.option.width || 200,             ch = this.el.height = this.option.height || 40;         }     } } 

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

2.绘制干扰线

// 画干扰线 drawLine: function(ctx, lineNum, maxW, maxH) {      ctx.clearRect(0, 0, maxW, maxH);     for(var i=0; i < lineNum; i++) {          var dx1 = Math.random()* maxW,             dy1 = Math.random()* maxH,             dx2 = Math.random()* maxW,             dy2 = Math.random()* maxH;         ctx.strokeStyle = rgb( + 255*Math.random() + , + 255*Math.random() + , + 255*Math.random() + );         ctx.beginPath();         ctx.moveTo(dx1, dy1);         ctx.lineTo(dx2, dy2);         ctx.stroke();     } } 

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

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

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

// 生成唯一文字 generateUniqueText: function(source, hasList, limit) {      var text = source[Math.floor(Math.random()*limit)];     if(hasList.indexOf(text) > -1) {          return this.generateUniqueText(source, hasList, limit)     }else {          return text     }   } // 生成指定个数的随机文字 randomText: function(len) {      var source = [a, b, c, d, e,     f, g, h, i, j,      k, l, m, o, p,     q, r, s, t, u,     v, w, x, y, z];     var result = [];     var sourceLen = source.length;     for(var i=0; i< len; i++) {          var text = this.generateUniqueText(source, result, sourceLen);         result.push(text)     }     return result.join() } 

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

4.用canvas绘制文字

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

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

5.初始化和canvas点击事件

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

init: function() {      if(this.el.getContext) {          isSupportCanvas = true;         var ctx = this.el.getContext(2d),         // 设置画布宽高         cw = this.el.width = this.option.width || 200,         ch = this.el.height = this.option.height || 40,         textLen = this.option.textLen || 4,         lineNum = this.option.lineNum || 4;         var text = this.randomText(textLen);         this.onClick(ctx, textLen, lineNum, cw, ch);         this.drawLine(ctx, lineNum, cw, ch);         this.drawText(ctx, text, ch);     } } 

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

onClick: function(ctx, textLen, lineNum, cw, ch) {      var _ = this;     this.el.addEventListener(click, function(){          text = _.randomText(textLen);         _.drawLine(ctx, lineNum, cw, ch);         _.drawText(ctx, text, ch);     }, false) } 

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

new Gcode(#canvas_code, {          lineNum: 6,  // 可选         textLen: 4,  // 可选         width: 200,  // 可选         height: 50   // 可选     }) 

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

// canvas绘制图形验证码     (function(){          function Gcode(el, option) {              this.el = typeof el === string ? document.querySelector(el) : el;             this.option = option;             this.init();         }         Gcode.prototype = {              constructor: Gcode,             init: function() {                  if(this.el.getContext) {                      isSupportCanvas = true;                     var ctx = this.el.getContext(2d),                     // 设置画布宽高                     cw = this.el.width = this.option.width || 200,                     ch = this.el.height = this.option.height || 40,                     textLen = this.option.textLen || 4,                     lineNum = this.option.lineNum || 4;                     var text = this.randomText(textLen);                     this.onClick(ctx, textLen, lineNum, cw, ch);                     this.drawLine(ctx, lineNum, cw, ch);                     this.drawText(ctx, text, ch);                 }             },             onClick: function(ctx, textLen, lineNum, cw, ch) {                  var _ = this;                 this.el.addEventListener(click, function(){                      text = _.randomText(textLen);                     _.drawLine(ctx, lineNum, cw, ch);                     _.drawText(ctx, text, ch);                 }, false)             },             // 画干扰线             drawLine: function(ctx, lineNum, maxW, maxH) {                  ctx.clearRect(0, 0, maxW, maxH);                 for(var i=0; i < lineNum; i++) {                      var dx1 = Math.random()* maxW,                         dy1 = Math.random()* maxH,                         dx2 = Math.random()* maxW,                         dy2 = Math.random()* maxH;                     ctx.strokeStyle = rgb( + 255*Math.random() + , + 255*Math.random() + , + 255*Math.random() + );                     ctx.beginPath();                     ctx.moveTo(dx1, dy1);                     ctx.lineTo(dx2, dy2);                     ctx.stroke();                 }             },             // 画文字             drawText: function(ctx, text, maxH) {                  var len = text.length;                 for(var i=0; i < len; i++) {                      var dx = 30 * Math.random() + 30* i,                         dy = Math.random()* 5 + maxH/2;                     ctx.fillStyle = rgb( + 255*Math.random() + , + 255*Math.random() + , + 255*Math.random() + );                     ctx.font = 30px Helvetica;                     ctx.textBaseline = middle;                     ctx.fillText(text[i], dx, dy);                 }             },             // 生成指定个数的服务器托管随机文字             randomText: function(len) {                  var source = [a, b, c, d, e,                 f, g, h, i, j,                  k, l, m, o, p,                 q, r, s, t, u,                 v, w, x, y, z];                 var result = [];                 var sourceLen = source.length;                 for(var i=0; i< len; i++) {                      var text = this.generateUniqueText(source, result, sourceLen);                     result.push(text)                 }                 return result.join()             },             // 生成唯一文字             generateUniqueText: function(source, hasList, limit) {                  var text = source[Math.floor(Math.random()*limit)];                 if(hasList.indexOf(text) > -1) {                      return this.generateUniqueText(source, hasList, limit)                 }else {                      return text                 }               }         }         new Gcode(#canvas_code, {              lineNum: 6         })     })(); 

分享到:

滇ICP备2023006006号-16