技术汇总:第七章:三种验证方式

第一种验证码

 






b.html

    <!DOCTYPE html>
    <html>
     
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=9; IE=8; IE=7; IE=EDGE">
        <meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7" />
        <title>设置-个人信息</title>
     
    </head>
     
    <body>
     
    </body>
        <script type="text/javascript" src="jquery.min.js" ></script>
        <script type="text/javascript" src="a.js" ></script>
    <div class="code">
      <input type="text" value="" placeholder="请输入验证码(不区分大小写)" class="input-val">
      <canvas id="canvas" width="100" height="30"></canvas>
      <button class="btn">提交</button>
    </div>
    </html>

a.js

     
     $(function(){
      var show_num = [];
      draw(show_num);
      $("#canvas").on('click',function(){
       draw(show_num);
      })
      $(".btn").on('click',function(){
       var val = $(".input-val").val().toLowerCase();
       var num = show_num.join("");
       if(val==''){
        alert('请输入验证码!');
       }else if(val == num){
        alert('提交成功!');
        $(".input-val").val('');
        // draw(show_num);
       }else{
        alert('验证码错误!请重新输入!');
        $(".input-val").val('');
        // draw(show_num);
       }
      })
     })
     //生成并渲染出验证码图形
     function draw(show_num) {
      var canvas_width=$('#canvas').width();
      var canvas_height=$('#canvas').height();
      var canvas = document.getElementById("canvas");//获取到canvas的对象,演员
      var context = canvas.getContext("2d");//获取到canvas画图的环境,演员表演的舞台
      canvas.width = canvas_width;
      canvas.height = canvas_height;
      var sCode = "a,b,c,d,e,f,g,h,i,j,k,m,n,p,q,r,s,t,u,v,w,x,y,z,A,B,C,E,F,G,H,J,K,L,M,N,P,Q,R,S,T,W,X,Y,Z,1,2,3,4,5,6,7,8,9,0";
      var aCode = sCode.split(",");
      var aLength = aCode.length;//获取到数组的长度
      for (var i = 0; i < 4; i++) { //这里的for循环可以控制验证码位数(如果想显示6位数,4改成6即可)
       var j = Math.floor(Math.random() * aLength);//获取到随机的索引值
       // var deg = Math.random() * 30 * Math.PI / 180;//产生0~30之间的随机弧度
       var deg = Math.random() - 0.5; //产生一个随机弧度
       var txt = aCode[j];//得到随机的一个内容
       show_num[i] = txt.toLowerCase();
       var x = 10 + i * 20;//文字在canvas上的x坐标
       var y = 20 + Math.random() * 8;//文字在canvas上的y坐标
       context.font = "bold 23px 微软雅黑";
       context.translate(x, y);
       context.rotate(deg);
       context.fillStyle = randomColor();
       context.fillText(txt, 0, 0);
       context.rotate(-deg);
       context.translate(-x, -y);
      }
      for (var i = 0; i <= 5; i++) { //验证码上显示线条
       context.strokeStyle = randomColor();
       context.beginPath();
       context.moveTo(Math.random() * canvas_width, Math.random() * canvas_height);
       context.lineTo(Math.random() * canvas_width, Math.random() * canvas_height);
       context.stroke();
      }
      for (var i = 0; i <= 30; i++) { //验证码上显示小点
       context.strokeStyle = randomColor();
       context.beginPath();
       var x = Math.random() * canvas_width;
       var y = Math.random() * canvas_height;
       context.moveTo(x, y);
       context.lineTo(x + 1, y + 1);
       context.stroke();
      }
     }
     //得到随机的颜色值
     function randomColor() {
      var r = Math.floor(Math.random() * 256);
      var g = Math.floor(Math.random() * 256);
      var b = Math.floor(Math.random() * 256);
      return "rgb(" + r + "," + g + "," + b + ")";
     }

 jquery.min.js自己搞吧

第二种验证









index.html

    <!DOCTYPE html>
    <html>
    <head>
    <title>jQuery拖动滑块验证码代码</title>
    <meta charset="utf-8">
    <link href="css/drag.css" rel="stylesheet" type="text/css">
    <script src="js/jquery-1.7.2.min.js" type="text/javascript"></script>
    <script src="js/drag.js" type="text/javascript"></script>
    </head>
    <body>
     
    <center><br><br><br><div id="drag"></div></center>
     
    <script type="text/javascript">
    $('#drag').drag();
    </script>
     
    <div style="text-align:center;margin:50px 0; font:normal 14px/24px 'MicroSoft YaHei';">
    </div>
    </body>
    </html>

 js/drag.js

    /*
     * drag 1.0
     * create by tony@jentian.com
     * date 2015-08-18
     * 拖动滑块
     */
    (function($){
        $.fn.drag = function(options){
            var x, drag = this, isMove = false, defaults = {
            };
            var options = $.extend(defaults, options);
            //添加背景,文字,滑块
            var html = '<div class="drag_bg"></div>'+
                        '<div class="drag_text" onselectstart="return false;" unselectable="on">拖动滑块验证</div>'+
                        '<div class="handler handler_bg"></div>';
            this.append(html);
            
            var handler = drag.find('.handler');
            var drag_bg = drag.find('.drag_bg');
            var text = drag.find('.drag_text');
            var maxWidth = drag.width() - handler.width();  //能滑动的最大间距
            
            //鼠标按下时候的x轴的位置
            handler.mousedown(function(e){
                isMove = true;
                x = e.pageX - parseInt(handler.css('left'), 10);
            });
            
            //鼠标指针在上下文移动时,移动距离大于0小于最大间距,滑块x轴位置等于鼠标移动距离
            $(document).mousemove(function(e){
                var _x = e.pageX - x;
                if(isMove){
                    if(_x > 0 && _x <= maxWidth){
                        handler.css({'left': _x});
                        drag_bg.css({'width': _x});
                    }else if(_x > maxWidth){  //鼠标指针移动距离达到最大时清空事件
                        dragOk();
                    }
                }
            }).mouseup(function(e){
                isMove = false;
                var _x = e.pageX - x;
                if(_x < maxWidth){ //鼠标松开时,如果没有达到最大距离位置,滑块就返回初始位置
                    handler.css({'left': 0});
                    drag_bg.css({'width': 0});
                }
            });
            
            //清空事件
            function dragOk(){
                handler.removeClass('handler_bg').addClass('handler_ok_bg');
                text.text('验证通过');
                drag.css({'color': '#fff'});
                handler.unbind('mousedown');
                $(document).unbind('mousemove');
                $(document).unbind('mouseup');
            }
        };
    })(jQuery);
     
     

js/ jquery-1.7.2.min.js自己搞吧

 css/drag.css

 

  1. #drag{
  2. position: relative;
  3. background-color: #e8e8e8;
  4. width: 300px;
  5. height: 34px;
  6. line-height: 34px;
  7. text-align: center;
  8. }
  9. #drag .handler{
  10. position: absolute;
  11. top: 0px;
  12. left: 0px;
  13. width: 40px;
  14. height: 32px;
  15. border: 1px solid #ccc;
  16. cursor: move;
  17. }
  18. .handler_bg{
  19. background: #fff url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAY
  20. AAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA3hpVFh0WE1MOmNvbS5hZG
  21. 9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prY
  22. zlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBD
  23. b3JlIDUuNS1jMDIxIDc5LjE1NTc3MiwgMjAxNC8wMS8xMy0xOTo0NDowMCAgICAgICAgIj4gPHJkZjpSREY
  24. geG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZj
  25. pEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwL
  26. zEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3Vy
  27. Y2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmF
  28. sRG9jdW1lbnRJRD0ieG1wLmRpZDo0ZDhlNWY5My05NmI0LTRlNWQtOGFjYi03ZTY4OGYyMTU2ZTYiIHhtcE
  29. 1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NTEyNTVEMURGMkVFMTFFNEI5NDBCMjQ2M0ExMDQ1OUYiIHhtcE1NOk
  30. luc3RhbmNlSUQ9InhtcC5paWQ6NTEyNTVEMUNGMkVFMTFFNEI5NDBCMjQ2M0ExMDQ1OUYiIHhtcDpDcmVhdG
  31. 9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTQgKE1hY2ludG9zaCkiPiA8eG1wTU06RGVyaXZlZEZyb2
  32. 0gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo2MTc5NzNmZS02OTQxLTQyOTYtYTIwNi02NDI2YTNkOWU5Ym
  33. UiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6NGQ4ZTVmOTMtOTZiNC00ZTVkLThhY2ItN2U2ODhmMjE1Nm
  34. U2Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPS
  35. JyIj8+YiRG4AAAALFJREFUeNpi/P//PwMlgImBQkA9A+bOnfsIiBOxKcInh+yCaCDuByoswaIOpxwjciACFe
  36. gBqZ1AvBSIS5OTk/8TkmNEjwWgQiUgtQuIjwAxUF3yX3xyGIEIFLwHpKyAWB+I1xGSwxULIGf9A7mQkBwTlh
  37. BXAFLHgPgqEAcTkmNCU6AL9d8WII4HOvk3ITkWJAXWUMlOoGQHmsE45ViQ2KuBuASoYC4Wf+OUYxz6mQkgwA
  38. AN9mIrUReCXgAAAABJRU5ErkJggg==") no-repeat center;


  39. }
  40. .handler_ok_bg{
  41. background: #fff url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYA
  42. AAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA3hpVFh0WE1MOmNvbS5hZG9i
  43. ZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+
  44. IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUu
  45. NS1jMDIxIDc5LjE1NTc3MiwgMjAxNC8wMS8xMy0xOTo0NDowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6
  46. cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlw
  47. dGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8i
  48. IHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4
  49. bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJ
  50. RD0ieG1wLmRpZDo0ZDhlNWY5My05NmI0LTRlNWQtOGFjYi03ZTY4OGYyMTU2ZTYiIHhtcE1NOkRvY3VtZW50
  51. SUQ9InhtcC5kaWQ6NDlBRDI3NjVGMkQ2MTFFNEI5NDBCMjQ2M0ExMDQ1OUYiIHhtcE1NOkluc3RhbmNlSUQ9
  52. InhtcC5paWQ6NDlBRDI3NjRGMkQ2MTFFNEI5NDBCMjQ2M0ExMDQ1OUYiIHhtcDpDcmVhdG9yVG9vbD0iQWRv
  53. YmUgUGhvdG9zaG9wIENDIDIwMTQgKE1hY2ludG9zaCkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5z
  54. dGFuY2VJRD0ieG1wLmlpZDphNWEzMWNhMC1hYmViLTQxNWEtYTEwZS04Y2U5NzRlN2Q4YTEiIHN0UmVmOmRv
  55. Y3VtZW50SUQ9InhtcC5kaWQ6NGQ4ZTVmOTMtOTZiNC00ZTVkLThhY2ItN2U2ODhmMjE1NmU2Ii8+IDwvcmRm
  56. OkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+k+sHwwAA
  57. ASZJREFUeNpi/P//PwMyKD8uZw+kUoDYEYgloMIvgHg/EM/ptHx0EFk9I8wAoEZ+IDUPiIMY8IN1QJwENOgj
  58. 3ACo5gNAbMBAHLgAxA4gQ5igAnNJ0MwAVTsX7IKyY7L2UNuJAf+AmAmJ78AEDTBiwGYg5gbifCSxFCZoaBMC
  59. y4A4GOjnH0D6DpK4IxNSVIHAfSDOAeLraJrjgJp/AwPbHMhejiQnwYRmUzNQ4VQgDQqXK0ia/0I17wJiPmQN
  60. TNBEAgMlQIWiQA2vgWw7QppBekGxsAjIiEUSBNnsBDWEAY9mEFgMMgBk00E0iZtA7AHEctDQ58MRuA6wlLgG
  61. FMoMpIG1QFeGwAIxGZo8GUhIysmwQGSAZgwHaEZhICIzOaBkJkqyM0CAAQDGx279Jf50AAAAAABJRU5ErkJg
  62. gg==") no-repeat center;

  63. }
  64. #drag .drag_bg{
  65. background-color: #7ac23c;
  66. height: 34px;
  67. width: 0px;
  68. }
  69. #drag .drag_text{
  70. position: absolute;
  71. top: 0px;
  72. width: 300px;
  73. -moz-user-select: none;
  74. -webkit-user-select: none;
  75. user-select: none;
  76. -o-user-select:none;
  77. -ms-user-select:none;
  78. }

  

第三种验证


















index.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>滑动拼图验证码</title>
      <link rel="stylesheet" href="jigsaw.css">
      <style>
        .container {
          width: 310px;
          margin: 100px auto;
        }
        input {
          display: block;
          width: 290px;
          line-height: 40px;
          margin: 10px 0;
          padding: 0 10px;
          outline: none;
          border:1px solid #c8cccf;
          border-radius: 4px;
          color:#6a6f77;
        }
        #msg {
          width: 100%;
          line-height: 40px;
          font-size: 14px;
          text-align: center;
        }
        a:link,a:visited,a:hover,a:active {
          margin-left: 100px;
          color: #0366D6;
        }
     
      </style>
    </head>
    <body>
    <div class="container">
      <input value="admin" readonly/>
      <input type="password" value="1234567890" readonly/>
      <div id="captcha" style="position: relative"></div>
      <div id="msg"></div>
    </div>
    <script src="jigsaw.js"></script>
    <script>
      jigsaw.init(document.getElementById('captcha'), function () {
        document.getElementById('msg').innerHTML = '登录成功!'
      })
    </script>
    </body>
    </html>

jigsaw.css

    .block {
      position: absolute;
      left: 0;
      top: 0;
    }
     
    .sliderContainer {
      position: relative;
      text-align: center;
      width: 310px;
      height: 40px;
      line-height: 40px;
      margin-top: 15px;
      background: #f7f9fa;
      color: #45494c;
      border: 1px solid #e4e7eb;
    }
     
    .sliderContainer_active .slider {
      height: 38px;
      top: -1px;
      border: 1px solid #1991FA;
    }
     
    .sliderContainer_active .sliderMask {
      height: 38px;
      border-width: 1px;
    }
     
    .sliderContainer_success .slider {
      height: 38px;
      top: -1px;
      border: 1px solid #52CCBA;
      background-color: #52CCBA !important;
    }
     
    .sliderContainer_success .sliderMask {
      height: 38px;
      border: 1px solid #52CCBA;
      background-color: #D2F4EF;
    }
     
    .sliderContainer_success .sliderIcon {
      background-position: 0 0 !important;
    }
     
    .sliderContainer_fail .slider {
      height: 38px;
      top: -1px;
      border: 1px solid #f57a7a;
      background-color: #f57a7a !important;
    }
     
    .sliderContainer_fail .sliderMask {
      height: 38px;
      border: 1px solid #f57a7a;
      background-color: #fce1e1;
    }
     
    .sliderContainer_fail .sliderIcon {
      background-position: 0 -83px !important;
    }
    .sliderContainer_active .sliderText, .sliderContainer_success .sliderText, .sliderContainer_fail .sliderText {
      display: none;
    }
     
    .sliderMask {
      position: absolute;
      left: 0;
      top: 0;
      height: 40px;
      border: 0 solid #1991FA;
      background: #D1E9FE;
    }
     
    .slider {
      position: absolute;
      top: 0;
      left: 0;
      width: 40px;
      height: 40px;
      background: #fff;
      box-shadow: 0 0 3px rgba(0, 0, 0, 0.3);
      cursor: pointer;
      transition: background .2s linear;
    }
     
    .slider:hover {
      background: #1991FA;
    }
     
    .slider:hover .sliderIcon {
      background-position: 0 -13px;
    }
     
    .sliderIcon {
      position: absolute;
      top: 15px;
      left: 13px;
      width: 14px;
      height: 10px;
      background: url(http://cstaticdun.126.net//2.6.3/images/icon_light.f13cff3.png) 0 -26px;
      background-size: 34px 471px;
    }
     
    .refreshIcon {
      position: absolute;
      right: 0;
      top: 0;
      width: 34px;
      height: 34px;
      cursor: pointer;
      background: url(http://cstaticdun.126.net//2.6.3/images/icon_light.f13cff3.png) 0 -437px;
      background-size: 34px 471px;
    }

jigsaw.js

    (function (window) {
      const l = 42, // 滑块边长
        r = 10, // 滑块半径
        w = 310, // canvas宽度
        h = 155, // canvas高度
        PI = Math.PI
      const L = l + r * 2 // 滑块实际边长
     
      function getRandomNumberByRange(start, end) {
        return Math.round(Math.random() * (end - start) + start)
      }
     
      function createCanvas(width, height) {
        const canvas = createElement('canvas')
        canvas.width = width
        canvas.height = height
        return canvas
      }
     
      function createImg(onload) {
        const img = createElement('img')
        img.crossOrigin = "Anonymous"
        img.onload = onload
        img.onerror = () => {
          img.src = getRandomImg()
        }
        img.src = getRandomImg()
        return img
      }
      
      function createElement(tagName) {
        return document.createElement(tagName)
      }
     
      function addClass(tag, className) {
        tag.classList.add(className)
      }
     
      function removeClass(tag, className) {
        tag.classList.remove(className)
      }
      
      function getRandomImg() {
        return 'https://picsum.photos/300/150/?image=' + getRandomNumberByRange(0, 100)
      }
     
      function draw(ctx, operation, x, y) {
        ctx.beginPath()
        ctx.moveTo(x, y)
        ctx.lineTo(x + l / 2, y)
        ctx.arc(x + l / 2, y - r + 2, r, 0, 2 * PI)
        ctx.lineTo(x + l / 2, y)
        ctx.lineTo(x + l, y)
        ctx.lineTo(x + l, y + l / 2)
        ctx.arc(x + l + r - 2, y + l / 2, r, 0, 2 * PI)
        ctx.lineTo(x + l, y + l / 2)
        ctx.lineTo(x + l, y + l)
        ctx.lineTo(x, y + l)
        ctx.lineTo(x, y)
        ctx.fillStyle = '#fff'
        ctx[operation]()
        ctx.beginPath()
        ctx.arc(x, y + l / 2, r, 1.5 * PI, 0.5 * PI)
        ctx.globalCompositeOperation = "xor"
        ctx.fill()
      }
     
      function sum(x, y) {
        return x + y
      }
     
      function square(x) {
        return x * x
      }
     
      class jigsaw {
        constructor(el, success, fail) {
          this.el = el
          this.success = success
          this.fail = fail
        }
     
        init() {
          this.initDOM()
          this.initImg()
          this.draw()
          this.bindEvents()
        }
     
        initDOM() {
          const canvas = createCanvas(w, h) // 画布
          const block = canvas.cloneNode(true) // 滑块
          const sliderContainer = createElement('div')
          const refreshIcon = createElement('div')
          const sliderMask = createElement('div')
          const slider = createElement('div')
          const sliderIcon = createElement('span')
          const text = createElement('span')
     
          block.className = 'block'
          sliderContainer.className = 'sliderContainer'
          refreshIcon.className = 'refreshIcon'
          sliderMask.className = 'sliderMask'
          slider.className = 'slider'
          sliderIcon.className = 'sliderIcon'
          text.innerHTML = '向右滑动滑块填充拼图'
          text.className = 'sliderText'
     
          const el = this.el
          el.appendChild(canvas)
          el.appendChild(refreshIcon)
          el.appendChild(block)
          slider.appendChild(sliderIcon)
          sliderMask.appendChild(slider)
          sliderContainer.appendChild(sliderMask)
          sliderContainer.appendChild(text)
          el.appendChild(sliderContainer)
     
          Object.assign(this, {
            canvas,
            block,
            sliderContainer,
            refreshIcon,
            slider,
            sliderMask,
            sliderIcon,
            text,
            canvasCtx: canvas.getContext('2d'),
            blockCtx: block.getContext('2d')
          })
        }
     
        initImg() {
          const img = createImg(() => {
            this.canvasCtx.drawImage(img, 0, 0, w, h)
            this.blockCtx.drawImage(img, 0, 0, w, h)
            const y = this.y - r * 2 + 2
            const ImageData = this.blockCtx.getImageData(this.x, y, L, L)
            this.block.width = L
            this.blockCtx.putImageData(ImageData, 0, y)
          })
          this.img = img
        }
     
        draw() {
          // 随机创建滑块的位置
          this.x = getRandomNumberByRange(L + 10, w - (L + 10))
          this.y = getRandomNumberByRange(10 + r * 2, h - (L + 10))
          draw(this.canvasCtx, 'fill', this.x, this.y)
          draw(this.blockCtx, 'clip', this.x, this.y)
        }
     
        clean() {
          this.canvasCtx.clearRect(0, 0, w, h)
          this.blockCtx.clearRect(0, 0, w, h)
          this.block.width = w
        }
     
        bindEvents() {
          this.el.onselectstart = () => false
          this.refreshIcon.onclick = () => {
            this.reset()
          }
     
          let originX, originY, trail = [], isMouseDown = false
          this.slider.addEventListener('mousedown', function (e) {
            originX = e.x, originY = e.y
            isMouseDown = true
          })
          document.addEventListener('mousemove', (e) => {
            if (!isMouseDown) return false
            const moveX = e.x - originX
            const moveY = e.y - originY
            if (moveX < 0 || moveX + 38 >= w) return false
            this.slider.style.left = moveX + 'px'
            var blockLeft = (w - 40 - 20) / (w - 40) * moveX
            this.block.style.left = blockLeft + 'px'
     
            addClass(this.sliderContainer, 'sliderContainer_active')
            this.sliderMask.style.width = moveX + 'px'
            trail.push(moveY)
          })
          document.addEventListener('mouseup', (e) => {
            if (!isMouseDown) return false
            isMouseDown = false
            if (e.x == originX) return false
            removeClass(this.sliderContainer, 'sliderContainer_active')
            this.trail = trail
            const {spliced, TuringTest} = this.verify()
            if (spliced) {
              if (TuringTest) {
                addClass(this.sliderContainer, 'sliderContainer_success')
                this.success && this.success()
              } else {
                addClass(this.sliderContainer, 'sliderContainer_fail')
                this.text.innerHTML = '再试一次'
                this.reset()
              }
            } else {
              addClass(this.sliderContainer, 'sliderContainer_fail')
              this.fail && this.fail()
              setTimeout(() => {
                this.reset()
              }, 1000)
            }
          })
        }
     
        verify() {
          const arr = this.trail // 拖动时y轴的移动距离
          const average = arr.reduce(sum) / arr.length // 平均值
          const deviations = arr.map(x => x - average) // 偏差数组
          const stddev = Math.sqrt(deviations.map(square).reduce(sum) / arr.length) // 标准差
          const left = parseInt(this.block.style.left)
          return {
            spliced: Math.abs(left - this.x) < 10,
            TuringTest: average !== stddev, // 只是简单的验证拖动轨迹,相等时一般为0,表示可能非人为操作
          }
        }
     
        reset() {
          this.sliderContainer.className = 'sliderContainer'
          this.slider.style.left = 0
          this.block.style.left = 0
          this.sliderMask.style.width = 0
          this.clean()
          this.img.src = getRandomImg()
          this.draw()
        }
     
      }
     
      window.jigsaw = {
        init: function (element, success, fail) {
          new jigsaw(element, success, fail).init()
        }
      }
    }(window))