拼图验证码

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/oncemore520/article/details/85327454

由于我们的官网之前是那种数字验证码,还是被扒了,所以现在我们打算要搞一个拼图验证码,交给我后,让我研究研究。
首先需求是这样的:
1.在这里插入图片描述
两个图片都是后台传过来,所以不需要前端生成 ,小图的位置是随机的,把小图拖动到对应位置,释放小图,向后台发送请求,也就是把对应的x,y的坐标值发送给后台,这里我就不结合我们的项目的业务了,大概就是这样的。
2.分为pc站和m站,这里首先想到的就是pc站的图片拖拽我这里用的是mouse事件(做好浏览器的兼容),m站呢用touch事件,(注意取消到浏览器的默认行为),
3.我想知道为什么不用那个极验验证码的呢,好吧,我也不知道,需要自己写
其中遇到了好多好多小问题,先把代码贴出来吧,当然也在网上参考了其他大神写的东西。
首先m站的

<template>
  <div>
    <div v-show="hongbaoShow" class="yd-mask"  @touchmove="pop($event)" style="overflow-y:hidden"></div>
    <div class="yd-popup-center" style="height:auto;" :class="{'yd-popup-show':hongbaoShow}">
      <div
        class="yd-popup-content"
        id="content"
        @touchmove="pop($event)"
        style="border-radius:8px;"
      >
        <div style="position: relative;border:1px solid #000;border-radius:8px">
          <!--绑定按下事件-->
          <img id="app" :src="urlBig">
          <img
            @touchstart="down"
            @touchmove.stop="move"
            @touchend="end"
            :src="urlSmall"
            width="40"
            height="40"
            :style="{'position':absolute,'top':top+'px','left':left+'px'}"
            id="appsmall"
          >
          <slot></slot>
          <div style="">
            <span class="range">拖动滑块以完成验证</span>
            <span class="range" style="float:right" @click="refresh()">刷新</span>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import cusPopup from "@components/public/popup";
import { consts } from "@config/consts";
import { getslider } from "@service/getData";
export default {
  data() {
    return {
      positionX: 0,
      positionY: 0,
      odiv: null,
      disX: 0,
      disY: 0,
      f1: null,
      flag: false,
      absolute: "absolute",
      top: 0,
      left: 0,
      urlSmall: "", //小图url
      urlBig: "",
      flags: false,
      position: { x: 0, y: 0 },
      nx: "",
      ny: "",
      dx: "",
      dy: "",
      xPum: "",
      yPum: "",
      limitLeft: 100,
      limitTop: 140
    };
  },
  props: {
    callback: {
      type: Function,
      default() {
        return () => {
          console.log("enterback");
        };
      }
    },
    type: {
      type: String,
      default: "phone" //默认手机号码登录
    },
    hongbaoShow: {
      default: false
    }
  },
  mounted() {
    //禁止触发下拉刷新事件
    this.$store.state.app.stopDrag = true;
    document.body.style.overflow = 'hidden'
    document.body.style.height = '100%'
    this.getRandom();
    this.getslider();
    document.addEventListener(
      "touchmove",
      function() {
        // 判断默认行为是否可以被禁用
        if (event.cancelable) {
          // 判断默认行为是否已经被禁用
          if (!event.defaultPrevented) {
            event.preventDefault();
          }
        }
      },
      false
    );
  },
  created() {},
  methods: {
    getImgPath: consts.getImgPath,
    refresh() {
      this.getslider();
      this.getRandom();
    },
    over() {
      document.getElementById("appsmall").style.cursor = "move";
    },
    pop(event) {
      if (event.cancelable) {
        // 判断默认行为是否已经被禁用
        if (!event.defaultPrevented) {
          event.preventDefault();
        }
      }
    },
    //获取滑块验证图
    async getslider() {
      let res = await getslider();
      if (res.code == 0) {
        this.urlBig = res.data.image_data_big;
        this.urlSmall = res.data.image_data_small;
      }
    },
    //滑块位置随机
    getRandom() {
      this.left = Math.floor(Math.random() * this.limitLeft + 1);
      this.top = Math.floor(Math.random() * this.limitTop + 1);
    },
    // 实现移动端拖拽
    down() {
      this.flags = true;
      var touch;
      if (event.touches) {
        touch = event.touches[0];
      } else {
        touch = event;
      }
      this.position.x = touch.clientX;
      this.position.y = touch.clientY;
      this.dx = document.getElementById("appsmall").offsetLeft;
      this.dy = document.getElementById("appsmall").offsetTop;
    },
    move() {
      if (this.flags) {
        var touch;
        document.body.style.overflow = 'hidden'
        document.body.style.height = '100%'
        if (event.touches) {
          touch = event.touches[0];
        } else {
          touch = event;
        }
        this.nx = touch.clientX - this.position.x;
        this.ny = touch.clientY - this.position.y;
        this.xPum = this.dx + this.nx;
        this.yPum = this.dy + this.ny;
        //判断不能超出便界
        if (this.xPum < 0) {
          this.xPum = 0;
        }
        if (this.xPum > 320 - 40) {
          this.xPum = 280;
        }
        if (this.yPum < 0) {
          this.yPum = 0;
        }
        if (this.yPum > 140) {
          this.yPum = 140;
        }
        document.getElementById("appsmall").style.left = this.xPum + "px";
        document.getElementById("appsmall").style.top = this.yPum + "px";

        //阻止页面的滑动默认事件;如果碰到滑动问题,1.2 请注意是否获取到 touchmove
        document.addEventListener(
          "touchmove",
          function() {
            if (event.cancelable) {
              // 判断默认行为是否已经被禁用
              if (!event.defaultPrevented) {
                event.preventDefault();
              }
            }
          },
          false
        );
      }
    },
    //鼠标释放时候的函数
    end() {
      this.flags = false;

      let data = {
        disX: this.xPum,
        disY: this.yPum,
        geturl: this.getslider()
      };
      this.callback(data);
      this.getRandom();
    }
  }
};
</script>
<style>
#app {
  width: 100%;
  height: 180px;
  /* background: #666; */
  /* position: absolute;  */
  top: 0;
  cursor: pointer;
}
body {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}
html {
  overflow: hidden;
}
.yd-mask {
  pointer-events: auto !important;
}
#codeImg {
  /*定位*/
  top: 10px;
  left: 10px;
}
.range {
  font-family: PingFangSC-Regular;
  font-size: 14px;
  color: #888888;
  letter-spacing: 0.12px;
  text-align: center;
}
#appsmall {
  touch-action: none;
  filter: drop-shadow(1px 1px 3px #000) drop-shadow(1px 1px 3px)
    drop-shadow(1px 1px 3px);
  -webkit-filter: drop-shadow(1px 1px 3px) drop-shadow(1px 1px 3px)
    drop-shadow(1px 1px 3px);
}
.yd-popup-center {
  width: 100%;
}
@media screen and (max-width: 320px) {
  .yd-popup-center {
    width: 100% !important;
  }
}
@media screen and (min-width: 320px) and (max-width: 359px) {
  .yd-popup-center {
    width: 320px !important;
  }
}
@media screen and (min-width: 360px) and (max-width: 374px) {
  .yd-popup-center {
    width: 320px !important;
  }
}
@media screen and (min-width: 375px) and (max-width: 385px) {
  .yd-popup-center {
    width: 320px !important;
  }
}
@media screen and (min-width: 386px) and (max-width: 392px) {
  .yd-popup-center {
    width: 320px !important;
  }
}
@media screen and (min-width: 393px) and (max-width: 400px) {
  .yd-popup-center {
    width: 320px !important;
  }
}
@media screen and (min-width: 401px) and (max-width: 414px) {
  .yd-popup-center {
    width: 320px !important;
  }
}
@media screen and (min-width: 750px) and (max-width: 799px) {
  .yd-popup-center {
    width: 320px !important;
  }
}
</style>
<style lang="less">
& .hongbao-popup {
  & .yd-popup-content {
    background: transparent !important;
    & .hongbao-content {
      height: 100%;
      & > .hb-close {
        position: absolute;
        top: 5px;
        right: 7px;
      }
      & > .hb-context {
        padding: 150px 48px 0;
        color: #333333;
        & > .hb-datetime {
          font-size: 15px;
          border-bottom: 1px dashed #333333;
          padding-bottom: 10px;
        }
        & > .hb-content {
          font-size: 15px;
          line-height: 1.6;
          padding: 10px 0;
        }
        & > .hb-notes {
          font-size: 13px;
        }
      }
    }
  }
}
</style>

这是自己封装好的一个组件,这里的弹窗用到了ydui的一个弹窗组件,popup弹窗。。也可以自己写弹窗。
这里解释其中几点:
A:在这里插入图片描述
这里只回传touchend的回调函数,避免用$emit,尽可能做到在在使用组件的时候做到最简单
B:在这里插入图片描述
注意这个样式,pointer-events这个属性是干嘛的,
在这里插入图片描述
所以啊,我用了弹窗之后,而这个弹窗恰巧人家封装的加上了这个属性,以至于我滑动滑块的时候就会触发下边的input的焦点触发事件。

基本上就是这些吧,现在直接粘贴出pc端的来吧

<template>
  <div style="position: relative;">
    <!--绑定按下事件-->
    <img id="app" :src="urlBig">
 
    <img    
      :src="urlSmall"
      width="40"
      height="40" 
      id="appsmall" :style="{'position':absolute,'top':top+'px','left':left+'px'}"  @mouseover="over"
      @mousedown="move"
    >
    <div style="margin-top:8px">
      <span class="range">拖动滑块以完成验证</span>
      <span class="range" style="float:right" @click="refresh()">刷新</span>
      <p style="text-align:center;color:red">{{tipmes}}</p>
    </div>
  </div>
</template>

<script>
import myDialog from "@components/public/dialog";
import { consts } from "@config/consts";
import { getslider } from "@service/getData";
export default {
  data() {
    return {
      positionX: 0,
      positionY: 0,
      odiv: null,
      disX: 0,
      disY: 0,
      f1: null,
      flag: false,
      absolute: "absolute",
      top: 0,
      left: 0,
      urlSmall: "", //小图url
      urlBig: "",
      limitLeft:100,
      limitTop:140
    };
  },
  props: {
    callback: {
      type: Function,
      default() {
        return () => {
          console.log("enterback");
        };
      }
    },
    type: {
      type: String,
      default: "phone" //默认手机号码登录
    },
    tipmes:{
      type:String
    }
  },
  mounted() {
    this.getRandom();
    this.getslider();
  },
  created() {},
  methods: {
    getImgPath: consts.getImgPath,
    refresh() {
      this.getslider();
      this.getRandom();
    },
    over() {
      document.getElementById("appsmall").style.cursor = "move";
    },
    //获取滑块验证图
    async getslider() {
      let res = await getslider();
      if (res.code == 0) {
        this.urlBig = res.data.image_data_big;
        this.urlSmall = res.data.image_data_small;
      }
    },
    //滑块位置随机
    getRandom() {
      this.left = Math.floor(Math.random() * this.limitLeft + 1);
      this.top = Math.floor(Math.random() * this.limitTop + 1);
    },
    move(e) {
      var e = e ? e : window.e;
      this.odiv = e.target; //获取目标元素
      //算出鼠标相对元素的位置
      this.disX = e.clientX - this.odiv.offsetLeft;
      this.disY = e.clientY - this.odiv.offsetTop;
      //浏览器的兼容性
      if (document.addEventListener) {
        let that = this;
        e.preventDefault && e.preventDefault();
        let f1 = function bodyScroll(e) {
          that.init(e);
        };
        let f2 = function removeScroll(e) {
          let data = {
            disX: that.positionX,
            disY: that.positionY,
            geturl: this.tipmes == '校验成功!' ? '' : that.getslider()
          };
          that.callback(data);
          that.getRandom();
          document.removeEventListener("mousemove", f1, false);
          document.removeEventListener("mouseup", f2, false);
        };
        document.addEventListener("mousemove", f1, false);
        document.addEventListener("mouseup", f2, false);
      } else if (document.attachEvent) {
        let that = this;
        e.preventDefault && e.preventDefault();
        let f1 = function bodyScroll(e) {
          that.init(e);
          that.flag = true;
        };
        let f2 = function removeScroll(e) {
          let data = {
            disX: that.positionX,
            disY: that.positionY,
            geturl: that.getslider()
          };
          that.callback(data);
          that.getRandom();
          document.detachEvent("onmousemove", f1, false);
          document.detachEvent("onmouseup", f2, false);
        };
        document.addEventListener("onmousemove", f1, false);
        document.addEventListener("onmouseup", f2, false);
      } else {
        let that = this;
        document.onmousemove = e => {
          that.init(e);
        };
        document.onmouseup = e => {
          let data = {
            disX: that.positionX,
            disY: that.positionY,
            geturl: that.getslider()
          };
          that.callback(data);
          that.getRandom();
          that.initdown();
        };
      }
    },
    init(e) {
      //用鼠标的位置减去鼠标相对元素的位置,得到元素的位置
      let left = e.clientX - this.disX;
      let top = e.clientY - this.disY;
      //判断不能超出便界
      if (left < 0) {
        left = 0;
      }
      if (left > 320 - 40) {
        left = 280;
      }
      if (top < 0) {
        top = 0;
      }
      if (top > 140) {
        top = 140;
      }
      //绑定元素位置到positionX和positionY上面
      this.positionX = top;
      this.positionY = left;

      //移动当前元素
      this.odiv.style.left = left + "px";
      this.odiv.style.top = top + "px";
    },
    initdown(e) {
      document.onmousemove = null;
      document.onmouseup = null;
      console.log(this.disX);
      console.log(this.disY);
    }
  }
};
</script>
<style>
#app {
  width: 320px;
  height: 180px;
  /* background: #666; */
  /* position: absolute;  */
  top: 0;
  cursor: pointer;
}
#codeImg {
  /*定位*/
  top: 10px;
  left: 10px;
}
.range {
  font-family: PingFangSC-Regular;
  font-size: 14px;
  color: #888888;
  letter-spacing: 0.12px;
  text-align: center;
}
#appsmall{
  filter: drop-shadow(1px 1px 3px #000) drop-shadow(1px 1px 3px) drop-shadow(1px 1px 3px);-webkit-filter: drop-shadow(1px 1px 3px) drop-shadow(1px 1px 3px) drop-shadow(1px 1px 3px);
}
</style>

猜你喜欢

转载自blog.csdn.net/oncemore520/article/details/85327454