JS implements three verification code effects

foreword

I practiced a few js exercises this week, all about verification codes. Among them, the picture verification code and digital verification code need to use canvas. Here I want to write a little about verification code knowledge.

  • One of the functions of the verification code is to reduce the pressure on the server. Just imagine that if many clients need to send login or registration information to the server at the same time, the server will be very busy. We can use the verification code to change the state of many users sending messages at the same time into the state of many users sending messages at different times. This will reduce the pressure on the server. Therefore, the verification code is a small effect that is necessary to use.
  • When writing a picture verification code, you need to pay attention: to load a picture image, you need to send an HTTP request. Loading multiple sheets requires sending multiple times. The verification codebook is to reduce the pressure on the server, but if there is HTTP for pictures, it will undoubtedly have the opposite effect. Therefore, the performance of the image needs to be optimized. There are several ways:
    • Reduce HTTP requests. Integrate dozens of small pictures into one big picture.
    • Base64
    • font icon. Render icons as fonts. You can change some styles of the whole picture, such as background color, etc., by changing the css style.

The summary ideas and codes of the three verification codes are as follows:

1. Simple verification code

1. The effect is as follows:
insert image description here
2. Thinking analysis:
such a verification code effect has these functions:

  • The slider slides halfway, and the mouse releases the slider to return to the original position
  • The text in the box when the slider slides to the end shows that the verification is successful and the slider pattern changes to a check mark.
  • During the entire process from the initial position, the mouse is pressed, and the final verification is successful, the mouse is always on the slider, and the slider moves with the mouse, and the background color green also increases. If you move or release the mouse after success, the effect will not change.

So how to achieve it?

  • A div element representing the slider is required for relative positioning, a div element representing the background color is relatively positioned, and a div element representing the text in the box is required. These three div elements are absolutely positioned by a parent div element.
  • mousedownWhat needs to be done is: bind the mouse down event in the slider element mousedown. Once this event is triggered, first mark e.clientXthe position where the mouse is pressed.
  • mousemoveWhat needs to be done is:
    • Bind the mouse movement event in the slider element mousemove, and also record the mouse position at this time e.clientX.

    • Calculate the difference. It should be noted here that the mouse movement must be triggered after the mouse is pressed to have an effect. If you move the mouse directly without first pressing it, it will have no effect. The reason for marking twice is to calculate the width of the background color green e.clientXbased on the difference between the two . moveXYou know, after a mouse press, the mouse movement is constantly triggered. Then this difference is also constantly changing. As shown below:
      insert image description here

      This difference moveXis not only the pixel value that the slider moves relative to the parent element, but also the width value of the background color.

    • judge moveX. Only when moveXthe value of is greater than 0, moveXthe width of the background color and the left value of the slider will change. Further judge that if the slider slides to the end, cancel the mouse press and move events. And the text in the box changes the pattern in the slider. Outside of this range, mouse move events have no effect. How to judge that the slider slides to the end, as shown in the following figure:
      insert image description here

  • mouseupWhat needs to be done is: bind the mouse removal event on the slider element. First of all, we need to know that if the slider has been moved to the end, the mouse removal event will not work. A flag can be added, which is true when the verification is successful. The mouse removal event will only work when the judgment flag is false. What the mouse removal event does is to enable the slider to move to its original position.
    And at the end of the removal event, the mouse movement event should be cleared. The reason for this step is that when the slider is pressed for the first time to move to the middle of the frame and then the slider is released to move to the original position, if the mouse movement event still exists, the slider can be moved without pressing it again. But the effect we need to achieve is to move the slider to take effect after the mouse is pressed again after moving to the initial position.

3. Source code:
html:

<body>
    <div class="box">
       <div class="word">拖动滑块验证</div>
       <div class="square"></div>
       <div class="bg"></div>
    </div>
</body>

css:

*{
    
    
    margin:0;
    padding:0;
}
.box{
    
    
    position: relative;
   width: 400px;
   height:40px;
   margin-left:400px;
   margin-top:20px;
   background-color:#DCDCDC;
}
.word{
    
    
   width:100%;
   height:100%;
   line-height:40px;
   text-align:center;
   -webkit-user-select:none;
}
.square{
    
    
    position: absolute;
    top:0;
    left:0;
    width:40px;
    height:40px;
    box-sizing: border-box;
    background-image:url("滑块 (1).png");
    background-size:100% 100%;
    background-repeat:no-repeat;
    background-color:#fff;
    border:1px solid #dcdcdc;
}
.bg{
    
    
    position: absolute;
    top:0;
    left:0;
    height:40px;
    width:0px;
    background-color:green;
    opacity:0.4;
}

js:

var btn={
    
    
    word:document.getElementsByClassName('word')[0],
    square:document.getElementsByClassName('square')[0],
    bg:document.getElementsByClassName('bg')[0],
    box:document.getElementsByClassName('box')[0],
    flag:false,
    down:function(){
    
    
       this.square.onmousedown=(e)=>{
    
    
           const downX=e.clientX;
           this.square.onmousemove=(e)=>{
    
    
                const nowX=e.clientX;
                let moveX=nowX-downX;
               if(moveX>0){
    
    
                this.square.style.left=moveX+'px';
                this.bg.style.width=moveX+'px';
                if(moveX>=this.box.offsetWidth-this.square.offsetWidth){
    
    
                    this.square.onmousedown=null;
                    this.square.onmousemove=null;
                    this.word.innerText="验证成功";
                    this.word.style.color="#fff";
                    this.flag=true;
                    this.square.style.backgroundImage="url('验证成功 (1).png')";
                }
               }
           }
       }
    },
    up:function(){
    
    
         this.square.onmouseup=()=>{
    
    
             if(this.flag) return;
             this.square.style.left=0;
             this.bg.style.width=0;
             this.square.onmousemove=null;
         }
    }
}
btn.down();
btn.up();

2. Slider verification code

1. The effect is as follows:
insert image description here
2. Source code:
html:

<body>
    <div class="wrapper">
        <div class="cap"></div>
    </div>
</body>

css:

*{
    
    
    margin:0;
    padding:0;
}
.wrapper{
    
    
    width:310px;
    margin:100px auto;
}
.cap{
    
    
    position: relative;
}
.block{
    
    
    position: absolute;
    top:0;
    left:0;
}
.sliderContainer{
    
    
  position: relative;
   width: 310px;
   height:40px;
   margin-top:15px;
   background-color:#DCDCDC;
}
.word{
    
    
   width:100%;
   height:100%;
   line-height:40px;
   text-align:center;
   -webkit-user-select:none;
}
.square{
    
    
    position: absolute;
    top:0;
    left:0;
    width:40px;
    height:40px;
    box-sizing: border-box;
    background-color:#fff;
    border:1px solid #dcdcdc;
    transition: background .2s linear;
}
.bg{
    
    
    position: absolute;
    top:0;
    left:0;
    box-sizing: border-box;
    height:40px;
    width:0px;
}
.bgActive{
    
    
    background-color:#D1E9FE;
    border:1px solid #1991FA;
}
.squareActive{
    
    
    border-width:0px;
}
.square:hover{
    
    
    border-width:0px;
    background-color:#1991FA;
}
.squareFail{
    
    
    background-color:#f57a7a!important;
}
.bgFail{
    
    
    border: 1px solid #f57a7a;
    background-color: #fce1e1;
}
.squareSuccess{
    
    
    background-color:#52CCBA!important;
}
.bgSuccess{
    
    
    border: 1px solid #52CCBA;
    background-color: #D2F4EF;
}
.refreshIcon{
    
    
    position: absolute;
    top:0;
    right:0;
    width:20px;
    height:20px;
    background-image:url("更新.png");
    background-size:100% 100%;
    background-repeat:no-repeat;
}

js:

function getNumberRange(start,end){
    
    
    return Math.floor(Math.random()*(end-start)+start);
}
function getImageUrl(){
    
    
    return 'https://picsum.photos/300/150/?image=' + getNumberRange(0, 100);
}
function createImage(loading){
    
    
    let img=document.createElement('img');
    //允许跨域
    img.crossOrigin="Anonymous";
    img.onload=loading;
    img.onerror=function(){
    
    
        img.src=getImageUrl();
    }
    img.src=getImageUrl();
    return img;
}
function addClass(tag,name){
    
    
    tag.classList.add(name);
}
var obj={
    
    
    l : 42, // 滑块边长
    r :10, // 滑块半径
    w :310, // canvas宽度
    h : 155, // canvas高度
    PI :Math.PI,
    init(el){
    
    
      this.cap=el;
      this. L =this.l + this.r * 2;//滑块实际边长
      this.y=getNumberRange(this.r*2-2,this.h-this.l);
      this.x=getNumberRange(this.L,this.w-this.L+2);
      this.initDOM();
      this.initImage();
      this.draw(); 
      this.move();
      this.refresh();
    },
    initDOM:function(){
    
    
       let canvas=document.createElement('canvas');
       canvas.setAttribute('class','ctx');
       canvas.width=this.w;
       canvas.height=this.h;
       let refreshIcon=document.createElement('div');
       refreshIcon.setAttribute('class','refreshIcon');
       let block=document.createElement('canvas');
       block.setAttribute('class','block');
       block.height=this.h;
       this.cap.appendChild(canvas);
       this.cap.appendChild(refreshIcon);
       this.cap.appendChild(block);
       let sliderContainer=document.createElement('div');
       sliderContainer.setAttribute('class','sliderContainer');
       let word=document.createElement('div');
       word.setAttribute('class','word');
       word.innerText="向右滑动滑块填充拼图"
       let square=document.createElement('square');
       square.setAttribute('class','square');
       let bg=document.createElement('bg');
       bg.setAttribute('class','bg');
       sliderContainer.appendChild(word);
       sliderContainer.appendChild(square);
       sliderContainer.appendChild(bg);
       this.cap.appendChild(sliderContainer);
       Object.assign(this,{
    
    
           canvasctx:canvas.getContext('2d'),
           refreshIcon,
           block,
           canvas,
           blockctx:block.getContext('2d'),
           sliderContainer,
           word,
           square,
           bg
       })
    },
    initImage:function(){
    
    
        let self=this;
        let img=createImage(function(){
    
    
            self.canvasctx.drawImage(img,0,0,self.w,self.h);
            self.blockctx.drawImage(img,0,0,self.w,self.h);
            const y=self.y-2*self.r+2;
            let imageData=self.blockctx.getImageData(self.x,y,self.L,self.L);
            self.block.width=self.L;
            self.blockctx.putImageData(imageData,0,y);
        });
    },
    draw(){
    
    
        let self=this;
        self.drawing(self.canvasctx,'fill',self.x,self.y);
        self.drawing(self.blockctx,'clip',self.x,self.y);
    },
    drawing(ctx,ope,x,y){
    
    
        ctx.beginPath();
        ctx.moveTo(x,y);
        ctx.lineTo(x+this.l/2,y);
        ctx.arc(x+this.l/2,y-this.r+2,this.r,0*this.PI,2*this.PI);
        ctx.lineTo(x+this.l/2,y);
        ctx.lineTo(x+this.l,y);
        ctx.lineTo(x+this.l,y+this.l/2);
        ctx.arc(x+this.l+this.r-2,y+this.l/2,this.r,0*this.PI,2*this.PI);
        ctx.lineTo(x+this.l,y+this.l/2);
        ctx.lineTo(x+this.l,y+this.l);
        ctx.lineTo(x,y+this.l);
        ctx.lineTo(x,y);
        ctx.fillStyle="#fff";
        ctx[ope]();
        ctx.beginPath();
        ctx.arc(x,y+this.l/2,this.r,1.5*this.PI,0.5*this.PI);
        ctx.globalCompositeOperation = "xor";
        ctx.fill();
    },
    clean:function(){
    
    
        this.blockctx.clearRect(0,0,this.w,this.h);
        this.canvasctx.clearRect(0,0,this.w,this.h);
        //!!!不加这句话不显示this.block画布,如果写这句话就会显示this.block画布
        this.block.width = this.w;
    },
    reset:function(){
    
    
        this.clean();
        this.square.style.left=0+'px';
        this.bg.style.width=0+'px';
        this.block.style.left=0+'px';
        this.square.className='square';
        this.bg.className='bg';
        this.word.innerText="向右滑动滑块填充拼图";
        this.y=getNumberRange(this.r*2-2,this.h-this.l);
        this.x=getNumberRange(this.L,this.w-this.L+2);
        this.initImage();
        this.draw();
        this.move();
    },
    refresh:function(){
    
    
       this.refreshIcon.onclick=()=>{
    
    
           this.reset();
       }
    },
    move:function(){
    
    
        let downX;
        this.square.onmousedown=(e)=>{
    
    
            downX=e.clientX;
            this.square.onmousemove=(e)=>{
    
    
                addClass(this.bg,'bgActive');
                addClass(this.square,'squareActive');
                this.word.innerText='';
                const nowX=e.clientX;
                let moveX=nowX-downX;
                if(moveX>0&&moveX<=this.sliderContainer.offsetWidth-this.square.offsetWidth){
    
    
                    this.square.style.left=moveX+'px';
                    this.bg.style.width=moveX+'px';
                    this.block.style.left=moveX+'px';
                }
        }
        this.square.onmouseup=(e)=>{
    
    
            const nowX=e.clientX;
            let moveX=nowX-downX;
            if(Math.abs(moveX-this.x)<=8){
    
    
                alert('验证成功');
                addClass(this.square,'squareSuccess');
                addClass(this.bg,'bgSuccess');
                this.square.onmousedown=null;
                this.square.onmousemove=null;
                this.word.style.color="#fff";
            }else{
    
    
                alert('验证失败');
                this.square.onmousemove=null;
                addClass(this.square,'squareFail');
                addClass(this.bg,'bgFail');
                setTimeout(()=>{
    
    
                    this.reset();
                },1500)
            }
       }
    }
}
}
obj.init(document.getElementsByClassName('cap')[0]);

3. Graphic verification code

1. The effect is as follows:
insert image description here

2. Source code:
html:

<body>
    <div class="picWrapper">
        <input type="text" class="inputText" value=''>
        <div id="pic"></div>
    </div>
</body>

css:

 *{
    
    
            margin:0;
            padding:0;
        }
        .picWrapper{
    
    
            width:400px;
            margin:100px auto;
        }
        .inputText{
    
    
            box-sizing: border-box;
            width:200px;
            height:30px;
            font-size:22px;
            float:left;
            margin-right:10px;
        }

js:

function randomNum(min,max){
    
    
    return Math.floor(Math.random()*(max-min)+min);
}
function randomColor(min,max){
    
    
    var a=randomNum(min,max);
    var b=randomNum(min,max);
    var c=randomNum(min,max);
    return 'rgb('+a+','+b+','+c+')';
}
function numArr(){
    
    
    return "0,1,2,3,4,5,6,7,8,9".split(',');
}
function letterArr(){
    
    
    return "a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z".split(',');
}
var obj={
    
    
    el: document.getElementsByClassName('inputText')[0],
    init:function(options){
    
    
       this.GVerify(options);
       this.initCanvas();
       this.refresh();
       this.fun();
    },
    //处理参数
    GVerify:function(options){
    
    
        this.options = {
    
     //默认options参数值
            id: "", //容器Id
            canvasId: "verifyCanvas", //canvas的ID
            width: "100", //默认canvas宽度
            height: "30", //默认canvas高度
            type: "blend", //图形验证码默认类型blend:数字字母混合类型、number:纯数字、letter:纯字母
            code: ""
        }
        //判断传入的参数
        if(Object.prototype.toString.call(options)=='[object Object]'){
    
    
            for(var i in options){
    
    
                this.options[i]=options[i];
            }
        }else{
    
    
            this.options.id=options;
        }
    },
    initCanvas:function(){
    
    
        var canvas=document.createElement('canvas');
        var parent=document.getElementById('pic');
        canvas.id=this.options.canvasId;
        canvas.width=this.options.width;
        canvas.height=this.options.height;
        canvas.style.cursor="pointer";
        canvas.onclick=()=>{
    
    
            this.refresh();
        }
        parent.appendChild(canvas);
    },
    refresh:function(){
    
    
        var self=this;
        self.options.code='';
        self.el.value='';
        var canvas=document.getElementById(self.options.canvasId);
        if(canvas.getContext){
    
    
            var ctx=canvas.getContext('2d');
            var ctxText;
            ctx.clearRect(0,0,self.options.width,self.options.height);
            //1.画图片
            ctx.fillStyle=randomColor(180,240);
            ctx.fillRect(0,0,self.options.width,self.options.height);
            ctx.textBaseline='middle';
            //2.画数字
            if(self.options.type=='blend'){
    
    
               ctxText=numArr().concat(letterArr());
            }else if(self.options.type=='number'){
    
    
               ctxText=numArr();
            }else{
    
    
               ctxText=letterArr();
            }
            for(var i=1;i<=4;++i){
    
    
               var num=ctxText[randomNum(0,ctxText.length-1)];
               var x=self.options.width/5*i;
               var y=self.options.height/2;
               var deg=randomNum(-30,30);
               ctx.font=randomNum(self.options.height/2,self.options.height)+'px SimHei';
               ctx.fillStyle = randomColor(50, 160); 
               ctx.shadowBlur=randomNum(-3,3);
               ctx.shadowColor='rgba(0,0,0,0.3)';
               ctx.translate(x,y);
               ctx.rotate(deg*Math.PI/180);
               ctx.fillText(num,0,0);
               self.options.code+=num;
               ctx.rotate(-deg*Math.PI/180);
               ctx.translate(-x,-y);
            }
            //3.画干扰线
            for(i=0;i<4;++i){
    
    
                var self=this;
                ctx.strokeStyle=randomColor(40,180);
                ctx.beginPath();
                ctx.moveTo(randomNum(0,self.options.width/2),randomNum(0,self.options.height/2));
                ctx.lineTo(randomNum(0,self.options.width/2),randomNum(0,self.options.height));
                ctx.stroke();
            }
            //4.画干扰点
            for(i=0;i<this.options.width/4;++i){
    
    
                var self=this;
                ctx.fillStyle=randomColor(0, 255);
                ctx.beginPath();
                ctx.arc(randomNum(0,self.options.width),randomNum(0,self.options.height),1,0,Math.PI*2);
                ctx.fill();
            }
        }
    },
    //判断输入的值与验证码的值是否一致
    judge:function(code){
    
    
        var code=code.toLowerCase();
        var options=this.options.code.toLowerCase();
        if(code==options){
    
    
            return true;
        }else{
    
    
            return false;
        }
    },
    //与input结合
    fun:function(){
    
    
        this.el.onmouseover=()=>{
    
    
            this.el.onmouseout=()=>{
    
    
                var code=this.el.value;
                if(code!=''){
    
    
                    var flag=this.judge(code);
                    if(!flag){
    
    
                        alert('验证码输入错误');
                        this.el.value='';
                        this.refresh();
                    }else{
    
    
                        alert('验证码输入正确');
                    }
                }
             }
        }
    }
}
obj.init("verifyCanvas");

Guess you like

Origin blog.csdn.net/qq_44875145/article/details/107560190