Canvas入门实战之用javascript面向对象实现一个图形验证码

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

你将收获

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

设计思路

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

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

效果预览

实现思路

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

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

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

  1. 绘制画布
1Gcode.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 } 12}

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

  1. 绘制干扰线
1// 画干扰线 2drawLine: 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 } 15}

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

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

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

1// 生成唯一文字 2generateUniqueText: 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// 生成指定个数的随机文字 11randomText: function(len) { 12 var source = ['a', 'b', 'c', 'd', 'e', 13 'f', 'g', 'h', 'i', 'j', 14 'k', 'l', 'm', 'o', 'p', 15 'q', 'r', 's', 't', 'u', 16 'v', 'w', 'x', 'y', 'z']; 17 var result = []; 18 var sourceLen = source.length; 19 for(var i=0; i< len; i++) { 20 var text = this.generateUniqueText(source, result, sourceLen); 21 result.push(text) 22 } 23 return result.join('') 24}

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

  1. 用canvas绘制文字
1// 画文字 2drawText: 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},

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

  1. 初始化和canvas点击事件

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

1init: 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 } 16}

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

1onClick: 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) 8}

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

1new 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 })();

如果想体验实际案例效果和技术交流,或者感受更多原创canvas,h5游戏demo,可以关注趣谈前端感受哈

更多推荐

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

一篇文章带你了解JavaScript日期

日期对象允许您使用日期(年、月、日、小时、分钟、秒和毫秒)。一、JavaScript的日期格式一个JavaScript日期可以写为一个字符串:ThuFeb02201909:59:51GMT0800(中国标准时间)或者是一个数字:1486000791164写数字的日期,指定的毫秒数自1970年1月1日00:00:00到现在。1\.显示日期使用