动态滑动图片验证码组件(支持多语言,移动端)

简介: 动态滑动图片验证码组件(支持多语言,移动端)

一、使用组件前的准备

因为组件用的是jQuery和canvas绘图,所以我们要提前在自己的项目里进行下载和引用,我这里用的是vue2.0,不知道如何在vue里面使用jQuery的小伙伴可以看之前分享过得如何在vue里使用jQuery

二、新建imgVer.js

function imgVer(Config) {
  var el = eval(Config.el);
  var w = Config.width;
  var h = Config.height;
  var imgLibrary = Config.img;
  var PL_Size = 48;
  var padding = 20;
  var MinN_X = padding + PL_Size;
  var MaxN_X = w - padding - PL_Size - PL_Size / 6;
  var MaxN_Y = padding;
  var MinN_Y = h - padding - PL_Size - PL_Size / 6;
  var bi = Config.lan;
  function RandomNum(minNum, maxNum) {
    switch (arguments.length) {
      case 1:
        return parseInt(Math.random() * minNum + 1, 10);
        break;
      case 2:
        return parseInt(Math.random() * (maxNum - minNum + 1) + minNum, 10);
        break;
      default:
        return 0;
        break;
    }
  }
  function lang(lnum, bi) {
    if (!bi) {
      bi = "cn";
    }
    var cn = new Array();
    cn["lan1"] = "按住左邊滑塊,拖動完成上方拼圖";
    cn["lan2"] = "驗證通過";
    cn["lan3"] = "驗證失敗";
    cn["lan4"] = "拖動滑塊將懸浮圖像正確拼合";
    var en = new Array();
    en["lan1"] = "Drag slider to finish the puzzle.";
    en["lan2"] = "Success";
    en["lan3"] = "Fail";
    en["lan4"] = "Complete the puzzle correctly.";
    return eval(bi)[lnum];
  }
  var imgRandom = RandomNum(1, imgLibrary.length) - 1;
  var imgSrc = imgLibrary[imgRandom];
  if (Config.randtox) {
    var X = Number(Config.randtox);
  } else {
    var X = RandomNum(MinN_X, MaxN_X);
  }
  var Y = RandomNum(MinN_Y, MaxN_Y);
  var left_Num = -X + 10;
  var html =
    '<div class="imgver_box"><div class="imgver_bg"></div><div class="imgver_main">';
  html +=
    '<div style="position:relative;padding:16px 16px 28px;border:1px solid #ddd;background:#f2ece1;border-radius:16px;">';
  html += '<div style="position:relative;overflow:hidden;width:' + w + 'px;">';
  html +=
    '<div style="position:relative;width:' + w + "px;height:" + h + 'px;">';
  html +=
    '<img id="scream" src="' +
    imgSrc +
    '" style="width:' +
    w +
    "px;height:" +
    h +
    'px;">';
  html +=
    '<canvas id="puzzleBox" width="' +
    w +
    '" height="' +
    h +
    '" style="position:absolute;left:0;top:0;z-index:22;"></canvas>';
  html += "</div>";
  html +=
    '<div class="puzzle-lost-box" style="position:absolute;width:' +
    w +
    "px;height:" +
    h +
    "px;top:0;left:" +
    left_Num +
    'px;z-index:111;">';
  html +=
    '<canvas id="puzzleShadow" width="' +
    w +
    '" height="' +
    h +
    '" style="position:absolute;left:0;top:0;z-index:22;"></canvas>';
  html +=
    '<canvas id="puzzleLost" width="' +
    w +
    '" height="' +
    h +
    '" style="position:absolute;left:0;top:0;z-index:33;"></canvas>';
  html += "</div>";
  html += '<p class="ver-tips"></p>';
  html += "</div>";
  html += '<div class="re-btn"><a></a></div>';
  html += "</div>";
  html += "<br>";
  html += '<div style="position:relative;width:' + w + 'px;margin:auto;">';
  html +=
    '<div style="border:1px solid #c3c3c3;border-radius:24px;background:#ece4dd;box-shadow:0 1px 1px rgba(12,10,10,0.2) inset;">';
  html +=
    '<div style="padding-left:26px;"><p style="font-size:12px;color:#486c80;line-height:28px;text-align:center;">' +
    lang("lan1", bi) +
    "</p></div>";
  html += "</div>";
  html += '<div class="slider-btn"></div>';
  html += "</div>";
  html += "</div></div>";
  el.html(html);
  var d = PL_Size / 3;
  var c = document.getElementById("puzzleBox");
  var ctx = c.getContext("2d");
  ctx.globalCompositeOperation = "xor";
  ctx.shadowBlur = 10;
  ctx.shadowColor = "#fff";
  ctx.shadowOffsetX = 3;
  ctx.shadowOffsetY = 3;
  ctx.fillStyle = "rgba(0,0,0,0.7)";
  ctx.beginPath();
  ctx.lineWidth = "1";
  ctx.strokeStyle = "rgba(0,0,0,0)";
  ctx.moveTo(X, Y);
  ctx.lineTo(X + d, Y);
  ctx.bezierCurveTo(X + d, Y - d, X + 2 * d, Y - d, X + 2 * d, Y);
  ctx.lineTo(X + 3 * d, Y);
  ctx.lineTo(X + 3 * d, Y + d);
  ctx.bezierCurveTo(
    X + 2 * d,
    Y + d,
    X + 2 * d,
    Y + 2 * d,
    X + 3 * d,
    Y + 2 * d
  );
  ctx.lineTo(X + 3 * d, Y + 3 * d);
  ctx.lineTo(X, Y + 3 * d);
  ctx.closePath();
  ctx.stroke();
  ctx.fill();
  var c_l = document.getElementById("puzzleLost");
  var c_s = document.getElementById("puzzleShadow");
  var ctx_l = c_l.getContext("2d");
  var ctx_s = c_s.getContext("2d");
  var img = new Image();
  img.src = imgSrc;
  img.onload = function() {
    ctx_l.drawImage(img, 0, 0, w, h);
  };
  ctx_l.beginPath();
  ctx_l.strokeStyle = "rgba(0,0,0,0)";
  ctx_l.moveTo(X, Y);
  ctx_l.lineTo(X + d, Y);
  ctx_l.bezierCurveTo(X + d, Y - d, X + 2 * d, Y - d, X + 2 * d, Y);
  ctx_l.lineTo(X + 3 * d, Y);
  ctx_l.lineTo(X + 3 * d, Y + d);
  ctx_l.bezierCurveTo(
    X + 2 * d,
    Y + d,
    X + 2 * d,
    Y + 2 * d,
    X + 3 * d,
    Y + 2 * d
  );
  ctx_l.lineTo(X + 3 * d, Y + 3 * d);
  ctx_l.lineTo(X, Y + 3 * d);
  ctx_l.closePath();
  ctx_l.stroke();
  ctx_l.shadowBlur = 10;
  ctx_l.shadowColor = "black";
  ctx_l.clip();
  ctx_s.beginPath();
  ctx_s.lineWidth = "1";
  ctx_s.strokeStyle = "rgba(0,0,0,0)";
  ctx_s.moveTo(X, Y);
  ctx_s.lineTo(X + d, Y);
  ctx_s.bezierCurveTo(X + d, Y - d, X + 2 * d, Y - d, X + 2 * d, Y);
  ctx_s.lineTo(X + 3 * d, Y);
  ctx_s.lineTo(X + 3 * d, Y + d);
  ctx_s.bezierCurveTo(
    X + 2 * d,
    Y + d,
    X + 2 * d,
    Y + 2 * d,
    X + 3 * d,
    Y + 2 * d
  );
  ctx_s.lineTo(X + 3 * d, Y + 3 * d);
  ctx_s.lineTo(X, Y + 3 * d);
  ctx_s.closePath();
  ctx_s.stroke();
  ctx_s.shadowBlur = 20;
  ctx_s.shadowColor = "black";
  ctx_s.fill();
  var moveStart = "";
  $(".slider-btn").mousedown(function(e) {
    e = e || window.event;
    $(this).addClass("slider-hover");
    moveStart = e.pageX;
  });
  $(".slider-btn").on("touchstart", function(e) {
    var touch = e.originalEvent.targetTouches[0];
    moveStart = touch.pageX;
  });
  onmousemove = function(e) {
    e = e || window.event;
    var moveX = e.pageX;
    var d = moveX - moveStart;
    if (moveStart == "") {
    } else {
      if (d < 0 || d > w - padding - PL_Size) {
      } else {
        $(".slider-btn").css({ left: d + "px", transition: "inherit" });
        $("#puzzleLost").css({ left: d + "px", transition: "inherit" });
        $("#puzzleShadow").css({ left: d + "px", transition: "inherit" });
      }
    }
  };
  $(".slider-btn").on("touchmove", function(e) {
    var touch = e.originalEvent.targetTouches[0];
    $(this).addClass("slider-hover");
    var moveX = touch.pageX;
    var d = moveX - moveStart;
    if (moveStart == "") {
    } else {
      if (d < 0 || d > w - padding - PL_Size) {
      } else {
        $(".slider-btn").css({ left: d + "px", transition: "inherit" });
        $("#puzzleLost").css({ left: d + "px", transition: "inherit" });
        $("#puzzleShadow").css({ left: d + "px", transition: "inherit" });
      }
    }
  });
  onmouseup = function(e) {
    e = e || window.event;
    var moveEnd_X = e.pageX - moveStart;
    pizzend(moveEnd_X);
  };
  $(".slider-btn").on("touchend", function(e) {
    var touch = e.originalEvent.changedTouches[0];
    var moveEnd_X = touch.pageX - moveStart;
    pizzend(moveEnd_X);
  });
  function pizzend(moveEnd_X) {
    var ver_Num = X - 10;
    var deviation = 5;
    var Min_left = ver_Num - deviation;
    var Max_left = ver_Num + deviation;
    if (moveStart == "") {
    } else {
      if (Max_left > moveEnd_X && moveEnd_X > Min_left) {
        $(".ver-tips").html(
          '<i class="success"></i><span style="color:#42ca6b;">' +
            lang("lan2", bi) +
            "</span><span></span>"
        );
        $(".ver-tips").addClass("slider-tips");
        $(".puzzle-lost-box").addClass("imgver_hidden");
        $("#puzzleBox").addClass("imgver_hidden");
        setTimeout(function() {
          $(".ver-tips").removeClass("slider-tips");
          //imgVer(Config);
        }, 2000);
        Config.success();
      } else {
        $(".ver-tips").html(
          '<i class="fail"></i><span style="color:red;">' +
            lang("lan3", bi) +
            ':</span><span style="margin-left:4px;">' +
            lang("lan4", bi) +
            "</span>"
        );
        $(".ver-tips").addClass("slider-tips");
        setTimeout(function() {
          $(".ver-tips").removeClass("slider-tips");
        }, 2000);
        Config.error();
      }
    }
    setTimeout(function() {
      $(".slider-btn").css({ left: "0", transition: "left 0.5s" });
      $("#puzzleLost").css({ left: "0", transition: "left 0.5s" });
      $("#puzzleShadow").css({ left: "0", transition: "left 0.5s" });
    }, 1000);
    $(".slider-btn").removeClass("slider-hover");
    moveStart = "";
    $(".re-btn a").on("click", function() {
      imgVer(Config);
    });
  }
}
export default imgVer;

这里导出后我直接在main.js做的全局挂载方便使用

1. import imgVer from "./js/imgver";
2. 
3. 
4. Vue.prototype.$imgVer = imgVer;

二、imgVer.css文件

@charset "utf-8";
#imgver {
  -moz-user-select: none;
  -webkit-user-select: none;
  -ms-user-select: none;
  -khtml-user-select: none;
  user-select: none;
}
.slider-btn,
.re-btn a,
.ver-tips i {
  background-image: url(../images/imgver/sprite.png);
}
.imgver_box {
  width: 100%;
  height: 100%;
  position: fixed;
  top: 0;
  left: 0;
  z-index: 10000;
}
.imgver_bg {
  width: 100%;
  height: 100%;
  background: rgba(0, 0, 0, 0.7);
  position: absolute;
  top: 0;
  left: 0;
  cursor: pointer;
}
.imgver_main {
  display: inline-block;
  position: absolute;
  top: 50%;
  margin-top: -103px;
  left: 50%;
  margin-left: -147px;
}
.slider-btn {
  position: absolute;
  width: 44px;
  height: 44px;
  left: 0;
  top: -7px;
  z-index: 12;
  cursor: pointer;
  background-position: 0 0;
  transition: inherit;
}
.slider-hover {
  background-position: 0 -44px;
}
.ver-tips {
  position: absolute;
  left: 0;
  bottom: -22px;
  background: rgba(255, 255, 255, 0.9);
  height: 22px;
  line-height: 22px;
  font-size: 12px;
  width: 100%;
  margin: 0;
  text-align: left;
  padding: 0 8px;
  transition: all 0.4s;
}
.slider-tips {
  bottom: 0;
}
.ver-tips i {
  display: inline-block;
  width: 22px;
  height: 22px;
  vertical-align: top;
}
.ver-tips i.success {
  background-position: 4px -122px;
}
.ver-tips i.fail {
  background-position: 4px -146px;
}
.ver-tips span {
  display: inline-block;
  vertical-align: top;
  line-height: 22px;
  color: #455;
}
.active-tips {
  display: block;
}
.imgver_hidden {
  display: none;
}
.re-btn {
  position: absolute;
  left: 0;
  bottom: 0;
  height: 28px;
  padding: 0 16px;
}
.re-btn a {
  display: inline-block;
  width: 14px;
  height: 14px;
  margin: 7px 0;
  background-position: 0 -88px;
  cursor: pointer;
}
.re-btn a:hover {
  background-position: 0 -102px;
}

三、layout.css 文件

@charset "utf-8";
body,
input,
textarea,
select,
button {
    font-family: "Arial", "PingFangSC-Light", "Microsoft Yahei", "宋体", sans-serif;
}
body {
    font-size: 12px;
    color: #000;
}
a {
    color: #000;
    text-decoration: none;
}
a:focus {
    outline: 0;
    -moz-outline: none;
}
/*for ff*/
a:hover {
    text-decoration: none;
    color: #ad1f24;
}
body,
div,
dl,
dt,
dd,
ul,
ol,
li,
h1,
h2,
h3,
h4,
h5,
h6,
pre,
code,
form,
fieldset,
legend,
input,
button,
textarea,
area,
blockquote,
th,
td,
p {
    margin: 0;
    padding: 0;
}
img,
a img,
button {
    border: 0;
}
table {
    border-collapse: collapse;
}
li {
    list-style-type: none;
}
input,
textarea,
select,
button {
    outline: none;
}
input,
textarea {
    resize: none;
    -webkit-appearance: none;
    border-radius: 0;
    border: 1px solid #ddd;
    width: 100%;
    box-sizing: border-box;
    min-height: 30px;
}
button[type="submit"],
input[type="submit"] {
    cursor: pointer;
}

样式文件我这里也是直接在main.js里面做的全局导入,方便使用;

import Vue from "vue";
import imgVer from "./js/imgver";
import "./assets/css/imgver.css";
import "./assets/css/layout.css";
Vue.config.productionTip = false;
Vue.use(ElementUI);
Vue.prototype.$axios = axios;
Vue.prototype.$imgVer = imgVer;

四、验证码背景图

位置随意即可

20210527153548522.png

image.png

Tips:

       这个sprite.psd文件下面有链接,大家可以下载

20210527153548522.png

五、页面内使用

        ·1.HTML

<van-form @submit="register" validate-first>
<div class="flex">
            <label>Home No.</label>
            <div>
              <div class="select-flex">
                <el-select
                  @change="getHouseNumber"
                  class="select-phone"
                  v-model="datas.selectHouseNumber"
                  placeholder="Please select"
                >
                  <el-option
                    v-for="item in areaCode"
                    :key="item.areaCode"
                    :value="item.areaCode"
                    :label="item.areaCode"
                  >
                  </el-option>
                </el-select>
                <van-field
                  v-model="datas.houseNumber"
                  type="number"
                  :rules="[
                    {
                      validator: validateHouseNumber,
                      message: houseNumberMessage,
                    },
                  ]"
                  class="field-phoneNumber"
                />
              </div>
            </div>
          </div>
          <div class="flex">
            <label>Email</label>
            <van-field
              v-model="datas.email"
              :rules="[
                {
                  validator: validateEmail,
                  message: 'Please enter a valid email',
                },
              ]"
              class="field"
            />
          </div>
</van-form>
<!-- 核心代码 -->
<div id="imgver"></div>

  2.methods中

register() {
      //核心代码
      this.$imgVer({
        el: '$("#imgver")',
        width: "260",
        height: "116",
        img: [
          require("@/assets/images/imgver/ver-1.png"),
          require("@/assets/images/imgver/ver-2.png"),
          require("@/assets/images/imgver/ver-3.png"),
          require("@/assets/images/imgver/ver-4.png"),
          require("@/assets/images/imgver/ver-5.png"),
          require("@/assets/images/imgver/ver-6.png"),
        ],
        //中英文切换
        lan: "en", //'cn' or 'en'
        success: () => {
        //成功的回调
          this.goRegister();
        },
        error: function () {
          return false;
        },
      });
    },

       3.效果图

20210527153548522.png

源码是可以进行后端验证的,今天给大家分享的用法只是在前端做随机;源码地址

相关文章
|
2月前
|
数据采集 自然语言处理 Python
用 Python 生成并识别图片验证码
用 Python 生成并识别图片验证码
52 1
|
4月前
|
SQL 前端开发 NoSQL
SpringBoot+Vue 实现图片验证码功能需求
这篇文章介绍了如何在SpringBoot+Vue项目中实现图片验证码功能,包括后端生成与校验验证码的方法以及前端展示验证码的实现步骤。
SpringBoot+Vue 实现图片验证码功能需求
|
5月前
【node】图片验证码(svg-captcha)
【node】图片验证码(svg-captcha)
293 0
|
6月前
|
前端开发 JavaScript 数据库
四. Django项目之电商购物商城 -- 图片验证码生成
四. Django项目之电商购物商城 -- 图片验证码生成
|
6月前
图片验证码制作(附源码)
图片验证码制作(附源码)
|
7月前
|
数据采集 安全 前端开发
Java如何制作图片输入验证码
Java如何制作图片输入验证码
65 0
|
7月前
|
Java 数据安全/隐私保护
Java 图片验证码需求分析
Java 图片验证码需求分析
80 0
|
Web App开发 Java
如何用java实现一个图片验证码
如何用java实现一个图片验证码
69 0
|
前端开发
react图形图片验证码重新请求图片不刷新
react图形图片验证码重新请求图片不刷新
121 0
|
PHP
PHP实现图片登录验证码的解决方案
PHP实现图片登录验证码的解决方案
126 0