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

一、使用组件前的准备

 因为组件用的是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做的全局挂载方便使用

import imgVer from "./js/imgver";


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;

四、验证码背景图

位置随意即可

 Tips:

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

 

 五、页面内使用

         ·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.效果图

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

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
你可以使用 React Swipeable 库来实现基于 React 的滑动图片验证码组件。该库提供了一个 Swipeable 组件,可以帮助你快速实现滑动操作。 下面是一个基本的滑动图片验证码组件的示例: ```jsx import React, { useState } from 'react'; import Swipeable from 'react-swipeable'; const SlideCaptcha = ({ onSuccess, onFailure }) => { const [isSliding, setIsSliding] = useState(false); const [sliderPosition, setSliderPosition] = useState(0); const [sliderWidth, setSliderWidth] = useState(0); const handleSwipeStart = () => { setIsSliding(true); }; const handleSwipeMove = (event, deltaX) => { if (!isSliding) return; const newSliderPosition = Math.max(0, Math.min(sliderWidth, sliderPosition + deltaX)); setSliderPosition(newSliderPosition); }; const handleSwipeEnd = () => { setIsSliding(false); if (sliderPosition >= sliderWidth * 0.9) { onSuccess(); } else { onFailure(); setSliderPosition(0); } }; const handleSliderRef = (node) => { if (node) { setSliderWidth(node.offsetWidth); } }; return ( <div> <div className="captcha-image" /> <Swipeable className="slider" onSwiping={handleSwipeMove} onSwipingStart={handleSwipeStart} onSwipingEnd={handleSwipeEnd} > <div className="slider-inner" ref={handleSliderRef}> <div className="slider-handle" style={{ left: sliderPosition }} /> </div> </Swipeable> </div> ); }; export default SlideCaptcha; ``` 在这个示例中,我们使用 Swipeable 组件来监听滑动事件,并根据滑动距离来移动滑块的位置。当滑块移动到指定位置时,触发 onSuccess 回调函数。如果滑块没有移动到指定位置,将调用 onFailure 回调函数并将滑块重置。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Iam_楠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值