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 相关文章推荐
json 实例详细说明教程
Oct 31 Javascript
JavaScript 原型继承之构造函数继承
Aug 26 Javascript
为Javascript中的String对象添加去除左右空格的方法(示例代码)
Nov 30 Javascript
如何在MVC应用程序中使用Jquery
Nov 17 Javascript
jQuery Mobile框架中的表单组件基础使用教程
May 17 Javascript
BootStrap树状图显示功能
Nov 24 Javascript
Jquery uploadify 多余的Get请求(404错误)的解决方法
Jan 26 Javascript
基于node.js之调试器详解
Aug 22 Javascript
Vue-cli中为单独页面设置背景色的实现方法
Feb 11 Javascript
基于node简单实现RSA加解密的方法步骤
Mar 21 Javascript
微信小程序用户授权弹窗 拒绝时引导用户重新授权实现
Jul 29 Javascript
react-native聊天室|RN版聊天App仿微信实例|RN仿微信界面
Nov 12 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
MySQL GBK→UTF-8编码转换
2007/05/24 PHP
非常不错的MySQL优化的8条经验
2008/03/24 PHP
PHPMailer邮件发送的实现代码
2013/05/04 PHP
php中的四舍五入函数代码(floor函数、ceil函数、round与intval)
2014/07/14 PHP
搜索附近的人PHP实现代码
2018/02/11 PHP
PHP使Laravel为JSON REST API返回自定义错误的问题
2018/10/16 PHP
PHP Include文件实例讲解
2019/02/15 PHP
学习YUI.Ext 第七天--关于View&amp;JSONView
2007/03/10 Javascript
jQuery实现表单input中提示文字value随鼠标焦点移进移出而显示或隐藏的代码
2010/03/21 Javascript
$.get获取一个文件的内容示例代码
2013/09/11 Javascript
在父页面得到zTree已选中的节点的方法
2015/02/12 Javascript
JavaScript模拟可展开、拖动与关闭的聊天窗口实例
2015/05/12 Javascript
JS如何实现文本框随文本的长度而增长
2015/07/30 Javascript
node使用UEditor富文本编辑器的方法实例
2017/07/11 Javascript
将 vue 生成的 js 上传到七牛的实例
2017/07/28 Javascript
NodeJS收发GET和POST请求的示例代码
2017/08/25 NodeJs
详解利用Angular实现多团队模块化SPA开发框架
2017/11/27 Javascript
浅谈webpack 构建性能优化策略小结
2018/06/13 Javascript
React之PureComponent的使用作用
2018/07/10 Javascript
Layui 解决表格异步调用后台分页的问题
2019/10/26 Javascript
vue element-ui el-date-picker限制选择时间为当天之前的代码
2019/11/07 Javascript
使用React-Router实现前端路由鉴权的示例代码
2020/07/26 Javascript
[33:42]LGD vs OG 2018国际邀请赛小组赛BO2 第一场 8.16
2018/08/17 DOTA
python之yield表达式学习
2014/09/02 Python
python实现二维码扫码自动登录淘宝
2016/12/27 Python
matplotlib绘图实例演示标记路径
2018/01/23 Python
PyQt5 pyqt多线程操作入门
2018/05/05 Python
python实现自动登录
2018/09/17 Python
pycharm使用matplotlib.pyplot不显示图形的解决方法
2018/10/28 Python
使用python绘制二元函数图像的实例
2019/02/12 Python
使用Python进行体育竞技分析(预测球队成绩)
2019/05/16 Python
python2和python3在处理字符串上的区别详解
2019/05/29 Python
CSS3 创建网页动画实现弹跳球动效果
2018/10/30 HTML / CSS
CSS3关于z-index不生效问题的解决
2020/02/19 HTML / CSS
HTML5打开手机扫码功能及优缺点
2017/11/27 HTML / CSS
2015小学教师年度考核工作总结
2015/05/12 职场文书