JavaScript Canvas实现验证码


Posted in Javascript onAugust 02, 2020

在通常的登录界面我们都可以看到验证码,验证码的作用是检测是不是人在操作,防止机器等非人操作,防止数据库被轻而易举的攻破。

验证码一般用PHP和java等后端语言编写。

但是在前端,用canva或者SVG也可以绘制验证码。

绘制验证码不能是简单的随机字符串,而应该在绘制界面有一些干扰项:

如:干扰线段、干扰圆点、背景等等。

这里的这个demo的canvas验证码干扰项比较简单。

可以在图示中看到本例中的干扰项。

canvas验证码展示效果:

点击实现改变(重绘)验证码:

JavaScript Canvas实现验证码

在控制台运行函数输出返回值(验证码):

JavaScript Canvas实现验证码

源码 :

<!DOCTYPE html>
<html lang="en">

<head>
 <meta charset="UTF-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <meta http-equiv="X-UA-Compatible" content="ie=edge">
 <title>canvas验证码</title>
</head>

<body>
 <canvas width="200" height="60" id="check" style="border:1px solid #000;">您的浏览器不支持canvas标签!</canvas>
 <script>
 var ctx = document.getElementById("check").getContext("2d");
 var ctxW = document.getElementById("check").clientWidth;
 var ctxH = document.getElementById("check").clientHeight;

 /**
  * 产生一个随机数 可设置随机数区间
  * @param {[Number]} min [随机数区间下限]
  * @param {[Number]} max [随机数区间上限]
  * @return {[Number]} [返回一个在此区间的随机数]
  */
 function ranNum(min, max) {

  return Math.random() * (max - min) + min;

 }

 /**
  * 返回一个随机颜色 可设置颜色区间
  * @param {[Number]} min [颜色下限]
  * @param {[Number]} max [颜色上限]
  * @return {[String]} [随机颜色]
  */
 function ranColor(min, max) {

  var r = ranNum(min, max);

  var g = ranNum(min, max);

  var b = ranNum(min, max);

  // return "rgb(" + r + "," + g + "," + b + ")";
  return `rgb(${r},${g},${b})`;

 }

 /**
  * 随机字符串数组
  * @return {[Array]} [随机数组]
  */
 function ranStr() {

  var str = "QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm0123456789";

  return str.split("").sort(function () {
  return Math.random() - 0.5
  });

 }

 /**
  * 绘制文本字符串
  * @param {[String]} canvasId [canvas的id]
  * @param {[Number]} canvasW [canvas的width]
  * @param {[Number]} canvasH [canvas的height]
  * @param {[Number]} num [绘制验证码的字数]
  * @param {[Number]} fsMin [字体大小下限]
  * @param {[Number]} fsMax [字体大小上限]
  * @param {[Number]} frMin [字体旋转偏移下限]
  * @param {[Number]} frMax [字体旋转偏移上限]
  * @param {[Number]} min [颜色下限]
  * @param {[Number]} max [颜色上限]
  * @return {[String]} [随机字符串]
  */
 function drawText(canvasId, canvasW, canvasH, num, fsMin, fsMax, frMin, frMax, min, max) {

  var str = "";

  for (var i = 0; i < num; i++) {

  var char = ranStr()[Math.floor(0, ranStr().length)];

  var fs = ranNum(fsMin, fsMax);

  canvasId.font = fs + "px Verdana";

  canvasId.fillStyle = ranColor(min, max);

  // 保存绘制的状态
  canvasId.save();

  // context.translate(x,y);
  // x 添加到水平坐标(x)上的值
  // y 添加到垂直坐标(y)上的值
  // 偏移
  canvasId.translate(canvasW / num * i + canvasW / 20, 0);

  // 变换角度
  canvasId.rotate(ranNum(frMin, frMax) * Math.PI / 180);

  // context.fillText(text,x,y,maxWidth);
  // text 规定在画布上输出的文本。
  // x 开始绘制文本的 x 坐标位置(相对于画布)。
  // y 开始绘制文本的 y 坐标位置(相对于画布)。
  // maxWidth 可选。允许的最大文本宽度,以像素计。
  canvasId.fillText(char, 0, (canvasH + fs) / 2.5, canvasW / num);

  // 返回之前保存过的路径状态和属性
  ctx.restore();

  str += char;

  }

  // console.log(str);
  return str;

 }

 /**
  * 绘制背景
  * @param {[String]} canvasId [canvas的id]
  * @param {[Number]} canvasW [canvas的width]
  * @param {[Number]} canvasH [canvas的height]
  * @param {[Number]} min [下限]
  * @param {[Number]} max [上限]
  */
 function drawBg(canvasId, canvasW, canvasH, min, max) {

  // 绘制canvas背景
  canvasId.fillStyle = ranColor(min, max);

  // 填充颜色
  canvasId.fillRect(0, 0, canvasW, canvasH);

 }

 /**
  * 绘制干扰 圆点
  * @param {[String]} canvasId [canvas的id]
  * @param {[Number]} canvasW [canvas的width]
  * @param {[Number]} canvasH [canvas的height]
  * @param {[Number]} num [绘制的数量]
  * @param {[Number]} r [圆点半径]
  * @param {[Number]} min [下限]
  * @param {[Number]} max [上线]
  */
 function drawCircle(canvasId, canvasW, canvasH, num, r, min, max) {

  for (var i = 0; i < num; i++) {

  // 开始绘制 (拿起笔)
  canvasId.beginPath();

  // context.arc(x,y,r,sAngle,eAngle,counterclockwise); (绘制)
  // x 圆的中心的 x 坐标。
  // y 圆的中心的 y 坐标。
  // r 圆的半径。
  // sAngle 起始角,以弧度计。(弧的圆形的三点钟位置是 0 度)。
  // eAngle 结束角,以弧度计。
  // counterclockwise 可选。规定应该逆时针还是顺时针绘图。False = 顺时针,true = 逆时针。
  canvasId.arc(ranNum(0, canvasW), ranNum(0, canvasH), r, 0, 2 * Math.PI);

  // 填充颜色
  canvasId.fillStyle = ranColor(min, max);

  // 填充
  canvasId.fill();

  // 闭合绘制 (放开笔)
  canvasId.closePath();

  }

 }

 /**
  * 绘制干扰 线段
  * @param {[String]} canvasId [canvas的id]
  * @param {[Number]} canvasW [canvas的width]
  * @param {[Number]} canvasH [canvas的height]
  * @param {[Number]} num [绘制的数量]
  * @param {[Number]} min [下限]
  * @param {[Number]} max [上线]
  */
 function drawLine(canvasId, canvasW, canvasH, num, min, max) {

  for (var i = 0; i < num; i++) {

  // 开始绘制 (拿起笔)
  canvasId.beginPath();

  // 绘制开始点
  canvasId.moveTo(ranNum(0, canvasW), ranNum(0, canvasH));

  // 绘制结束点
  canvasId.lineTo(ranNum(0, canvasW), ranNum(0, canvasH));

  canvasId.strokeStyle = ranColor(min, max);

  canvasId.stroke();

  canvasId.closePath();

  }

 }

 // 绘制验证码
 function drawCanvas() {

  // 清空canvas
  ctx.clearRect(0, 0, 200, 60);

  // 绘制背景
  drawBg(ctx, ctxW, ctxH, 200, 255);

  // 绘制干扰圆点
  drawCircle(ctx, ctxW, ctxH, 20, 5, 200, 255);

  // 绘制干扰线段
  drawLine(ctx, ctxW, ctxH, 20, 0, 255);

  // 绘制验证码
  var str = drawText(ctx, ctxW, ctxH, 4, 10, 50, -30, 30, 0, 100);

  return str;

 }

 drawCanvas();

 document.getElementById('check').onclick = drawCanvas;
 </script>
</body>

</html>

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
实现JavaScript中继承的三种方式
Oct 16 Javascript
随鼠标上下滚动的jquery代码
Dec 05 Javascript
node.js中的fs.truncateSync方法使用说明
Dec 15 Javascript
javascript中indexOf技术详解
May 07 Javascript
JavaScript驾驭网页-DOM
Mar 24 Javascript
玩转NODE.JS(四)-搭建简单的聊天室的代码
Nov 11 Javascript
jQuery中on方法使用注意事项详解
Feb 15 Javascript
jQuery实现ajax无刷新分页页码控件
Feb 28 Javascript
详解React Native网络请求fetch简单封装
Aug 10 Javascript
基于vue.js路由参数的实例讲解——简单易懂
Sep 07 Javascript
vue axios 表单提交上传图片的实例
Mar 16 Javascript
Vue模板语法中数据绑定的实例代码
May 17 Javascript
JS实现方形抽奖效果
Aug 27 #Javascript
对vuejs的v-for遍历、v-bind动态改变值、v-if进行判断的实例讲解
Aug 27 #Javascript
Vuex 在Vue 组件中获得Vuex 状态state的方法
Aug 27 #Javascript
JS实现匀速与减速缓慢运动的动画效果封装示例
Aug 27 #Javascript
vue展示dicom文件医疗系统的实现代码
Aug 27 #Javascript
vue中子组件的methods中获取到props中的值方法
Aug 27 #Javascript
最适应的vue.js的form提交涉及多种插件【推荐】
Aug 27 #Javascript
You might like
《PHP边学边教》(02.Apache+PHP环境配置――下篇)
2006/12/13 PHP
centos 5.6 升级php到5.3的方法
2011/05/14 PHP
php中防止伪造跨站请求的小招式
2011/09/02 PHP
PHP中PDO基础教程 入门级
2011/09/04 PHP
深入file_get_contents与curl函数的详解
2013/06/25 PHP
Avengerls vs Newbee BO3 第二场2.18
2021/03/10 DOTA
jQueryUI如何自定义组件实现代码
2010/11/14 Javascript
js操作checkbox遇到的问题解决
2013/06/29 Javascript
jQuery实现div浮动层跟随页面滚动效果
2014/02/11 Javascript
基于jQuery实现自动轮播旋转木马特效
2015/11/02 Javascript
Bootstrap编写一个兼容主流浏览器的受众巨幕式风格页面
2016/07/01 Javascript
bootstrap table操作技巧分享
2017/02/15 Javascript
EasyUI创建人员树的实例代码
2017/09/15 Javascript
react-native-fs实现文件下载、文本存储的示例代码
2017/09/22 Javascript
bootstrap paginator分页插件的两种使用方式实例详解
2017/11/14 Javascript
微信小程序首页的分类功能和搜索功能的实现思路及代码详解
2018/09/11 Javascript
Vuejs中的watch实例详解(监听者)
2020/01/05 Javascript
JS加载解析Markdown文档过程详解
2020/05/19 Javascript
Python 正则表达式操作指南
2009/05/04 Python
Python重新引入被覆盖的自带function
2014/07/16 Python
详解Python中的多线程编程
2015/04/09 Python
Python中单、双下划线的区别总结
2017/12/01 Python
Python 按字典dict的键排序,并取出相应的键值放于list中的实例
2019/02/12 Python
Python3标准库总结
2019/02/19 Python
如何使用pyinstaller打包32位的exe程序
2019/05/26 Python
Python 根据日志级别打印不同颜色的日志的方法示例
2019/08/08 Python
python列表删除和多重循环退出原理详解
2020/03/26 Python
Python在线和离线安装第三方库的方法
2020/10/31 Python
python连接手机自动搜集蚂蚁森林能量的实现代码
2021/02/24 Python
css3背景图片透明叠加属性cross-fade简介及用法实例
2013/01/08 HTML / CSS
美国波道夫·古德曼百货官网:Bergdorf Goodman
2017/11/07 全球购物
美国背景检查、公共记录和人物搜索网站:BeenVerified
2018/02/25 全球购物
美国优质马术服装购买网站:Breeches.com
2019/12/16 全球购物
关键字final的用法
2013/10/02 面试题
祖国在我心中演讲稿
2014/01/15 职场文书
法制宣传标语集锦
2014/06/25 职场文书