用户登录拖动验证码实现原理详解。

我们经常看到登录一些网站或者平台的时候会出现一些需要拖动验证码,实现验证功能,如斗鱼TV所示,于是就想了下这个要怎么实现,自己看了下他的html结构,是两个canvas,然后实现对接,原理应该是一个canvas作为背景然后,另一个canvas在原来的背景canvas里面扣一张图,然后拖动元素,当元素面积接近一个百分比的时候就认为两个元素重合了,验证通过了。大概就是这样的原理~!

于是自己想了下如果要自己去实现要怎么去实现这样一个效果,其实他这个划片是左右移动的,也只要移动的元素左边的距离left值达到一定数值的时候就可以表示重合了,这样就不需要计算重合面积了,但是自己如果是需求要求可以上下左右移动,那么又要怎么实现呢?

这个应该就属于数学问题了,就是两个正方形相交,相交面积怎么计算。

1、这个计算过程也不算难,首先可以getBoundingClientRect方法获取到元素距离窗口的left-top的值,就相当于计算出元素四个顶点的坐标值。

2、计算出坐标值之后再计算不动的那个元素X坐标的范围,Y坐标的范围。然后拖动元素的过程中判断拖动元素的哪个点在这个范围内,那么就可以知道图形相交的样子,就可以计算出相交的面积了。

3、计算面积去除总的面积就可以得出相交面积重合比例。

具体代码如下:


<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <!--<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0">-->
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta http-equiv="Cache-Control" content="no-cache" />
    <title>--TITLE--</title>
    <style>
      .box1, .box2 {
        height:200px;
        width:200px;
        background:red;
        text-align:center;
        line-height:200px;
        font-size:30px;
        user-select: none;
      }
      #MoveBox{
        position:absolute;
        background:blue;
      }
      .out-box {
        position:relative;
        height: 600px;
        width: 1000px;
        margin:200px auto;
      }
    </style>
  </head>
  <body>
    <div class="out-box">
      <div class="box1" id="staticBox">相对盒子</div>
      <div class="box2" id="MoveBox" style="left: 30px; top: 30px;">拖动盒子</div>
    </div>
    <script>
      // 求出两个元素是否相交 selem ,melem 分别为静止的盒子和移动的盒子
      const elemIntersect = (selem, melem) => {
        let msg = selem.getBoundingClientRect();
        let sArea = (msg.width * msg.height); // 静止盒子的面积
        let minX = msg.left;  // 静止元素左边最小
        let maxX = msg.left + msg.width;  // 静止元素右边最大
        let minY = msg.top; // 静止元素顶部最小
        let maxY = msg.top + msg.height;  // 静止元素顶部最大
        let mPoint = getPoint(melem); // 获取移动点四点的值
        // 左上点移入标识
        let flagLt = (mPoint.ltX >= minX && mPoint.ltX <= maxX) && (mPoint.ltY >= minY && mPoint.ltY <= maxY);
        // 左下点移入标识
        let flagLb = (mPoint.lbX >= minX && mPoint.lbX <= maxX) && (mPoint.lbY >= minY && mPoint.lbY <= maxY);
        // 右上点移入标识
        let flagRt = (mPoint.rtX >= minX && mPoint.rtX <= maxX) && (mPoint.rtY >= minY && mPoint.rtY <= maxY);
        // 右下点移入标识
        let flagRb = (mPoint.rbX >= minX && mPoint.rbX <= maxX) && (mPoint.rbY >= minY && mPoint.rbY <= maxY);

        if (flagLt) {
          console.log('左上点进去了');
          // 移动box的左上点减去静止盒子的右下点就为长和宽
          let boxArea = (getPoint(selem).rbX - getPoint(melem).ltX) * (getPoint(selem).rbY - getPoint(melem).ltY);
          console.log('相交部分的面积:' + boxArea);
          console.log('相交部分的面积占比:' + (boxArea / sArea) * 100 + '%');
        } else if (flagLb) {
          console.log('左下点进去了');
          // 静止box的右上点减去移动盒子的左下点就为长和宽
          let boxArea = (getPoint(selem).rtX - getPoint(melem).lbX) * (getPoint(melem).lbY - getPoint(selem).rtY);
          console.log('相交部分的面积:' + boxArea);
          console.log('相交部分的面积占比:' + (boxArea / sArea) * 100 + '%');
        } else if (flagRt) {
          console.log('右上点进去了');
          let boxArea = (getPoint(melem).rtX - getPoint(selem).lbX) * (getPoint(selem).lbY - getPoint(melem).rtY);
          console.log('相交部分的面积:' + boxArea);
          console.log('相交部分的面积占比:' + (boxArea / sArea) * 100 + '%');
        } else if (flagRb) {
          console.log('右下点进去了');
          let boxArea = (getPoint(melem).rbX - getPoint(selem).ltX) * (getPoint(melem).rbY - getPoint(selem).ltY);
          console.log('相交部分的面积:' + boxArea);
          console.log('相交部分的面积占比:' + (boxArea / sArea) * 100 + '%');
        } else {
          console.log('没有相交部分');
        }
      };
      // 获取元素四个点的坐标 
      const getPoint = (dom) => {
        let msg = dom.getBoundingClientRect();
        return {
          // 左上
          ltX: msg.left,
          ltY: msg.top,
          // 左下
          lbX: msg.left,
          lbY: msg.top + msg.height,
          // 右上
          rtX: msg.left + msg.width,
          rtY: msg.top,
          // 右下
          rbX: msg.left + msg.width,
          rbY: msg.top + msg.height,
        };
      };
      // 求出相交的面积
      const getRecArea = (id) => {
        let staticBox = document.querySelector('#staticBox'); // 静止的box
        let MoveBox = document.querySelector('#MoveBox'); // 移动的box
        let startX = null;
        let startY = null;
        let endX = null;
        let endY = null;
        let originX = null;
        let originY = null;
        let flag = false; // 鼠标按下标识
        // 鼠标点击移动box
        MoveBox.addEventListener('mousedown', function(e){
          flag = true;
          originX = parseFloat(MoveBox.style.left);
          originY = parseFloat(MoveBox.style.top);
          startX = e.clientX;
          startY = e.clientY;
          console.log(originX, originY, startX, startY)
        }, false);
        // 鼠标移动的时候
        document.addEventListener('mousemove', function(e){
          if (flag) {
            MoveBox.style.left = originX + (e.clientX - startX) + 'px';
            MoveBox.style.top = originY + (e.clientY - startY) + 'px';
            elemIntersect(staticBox, MoveBox);  // 求出相交部分的面积
          }
          // console.log(e);
        }, false);
        // 鼠标松开移动box
        MoveBox.addEventListener('mouseup', function(e){
          flag = false;
          console.log(e);
        }, false);
      };
      getRecArea();
    </script>
  </body>
</html>

运行结果如下:

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值