vue iview 前端集成 滑块验证码,通过拖动滑块完成校验支持PC端及移动端

滑块验证码,用户通过拖动滑块完成校验,支持PC端及移动端,新增 Blazor 版本的滑块验证码

在线演示地址

在这里插入图片描述

Gitee码云 git地址

在vue项目中通过 export 导出对象

这是项目本地js文件导入的正确方式,不要在script标签引入那是错误的

<script>
/* eslint-disable */
import { sliderCaptcha } from "@/assets/capcha/disk/longbow.slidercaptcha.js";
import "@/assets/capcha/disk/slidercaptcha.css";
export default {
  data() {
export let SliderCaptcha = function (element, options) {
    this.$element = $(element);
    this.options = $.extend({}, SliderCaptcha.DEFAULTS, options);
    this.$element.css({ 'position': 'relative', 'width': this.options.width + 'px', 'margin': '0 auto' });
    this.init();
};
// eslint-disable-next-line
SliderCaptcha.VERSION = '1.0';
SliderCaptcha.Author = 'argo@163.com';
SliderCaptcha.DEFAULTS = {
    width: 280,     // canvas宽度
    height: 155,    // canvas高度
    PI: Math.PI,
    sliderL: 42,    // 滑块边长
    sliderR: 9,     // 滑块半径
    offset: 5,      // 容错偏差
    loadingText: '正在加载中...',
    failedText: '再试一次',
    barText: '向右滑动填充拼图',
    repeatIcon: 'ivu-icon ivu-icon-ios-refresh',
    maxLoadCount: 3,
    // eslint-disable-next-line
    localImages: function () {
        return '';
    },
    // eslint-disable-next-line
    verify: function (arr, url) {
        var ret = false;
        $.ajax({
            url: url,
            data: JSON.stringify(arr),
            async: false,
            cache: false,
            type: 'POST',
            contentType: 'application/json',
            dataType: 'json',
            success: function (result) {
                ret = result;
            }
        });
        return ret;
    },
    remoteUrl: null
};
// eslint-disable-next-line
function Plugin(option) {
    return this.each(function () {
        var $this = $(this);
        var data = $this.data('lgb.SliderCaptcha');
        var options = typeof option === 'object' && option;

        if (data && !/reset/.test(option)) return;
        if (!data) $this.data('lgb.SliderCaptcha', data = new SliderCaptcha(this, options));
        if (typeof option === 'string') data[option]();
    });
}

$.fn.sliderCaptcha = Plugin;
$.fn.sliderCaptcha.Constructor = SliderCaptcha;

var _proto = SliderCaptcha.prototype;
_proto.init = function () {
    this.initDOM();
    this.initImg();
    this.bindEvents();
};

_proto.initDOM = function () {
    var createElement = function (tagName, className) {
        var elment = document.createElement(tagName);
        elment.className = className;
        return elment;
    };

    var createCanvas = function (width, height) {
        var canvas = document.createElement('canvas');
        canvas.width = width;
        canvas.height = height;
        return canvas;
    };
    var canvas = createCanvas(this.options.width - 2, this.options.height); // 画布
    var block = canvas.cloneNode(true); // 滑块
    var sliderContainer = createElement('div', 'sliderContainer');
    var refreshIcon = createElement('i', this.options.repeatIcon);
    var sliderMask = createElement('div', 'sliderMask');
    var sliderbg = createElement('div', 'sliderbg');
    var slider = createElement('div', 'slider');
    var sliderIcon = createElement('i', 'fa fa-arrow-right sliderIcon');
    var text = createElement('span', 'sliderText');

    block.className = 'block';
    text.innerHTML = this.options.barText;

    var el = this.$element;
    el.append($(canvas));
    el.append($(refreshIcon));
    el.append($(block));
    slider.appendChild(sliderIcon);
    sliderMask.appendChild(slider);
    sliderContainer.appendChild(sliderbg);
    sliderContainer.appendChild(sliderMask);
    sliderContainer.appendChild(text);
    el.append($(sliderContainer));

    var _canvas = {
        canvas: canvas,
        block: block,
        sliderContainer: $(sliderContainer),
        refreshIcon: refreshIcon,
        slider: slider,
        sliderMask: sliderMask,
        sliderIcon: sliderIcon,
        text: $(text),
        canvasCtx: canvas.getContext('2d'),
        blockCtx: block.getContext('2d')
    };

    if ($.isFunction(Object.assign)) {
        Object.assign(this, _canvas);
    }
    else {
        $.extend(this, _canvas);
    }
};

_proto.initImg = function () {
    var that = this;
    var isIE = window.navigator.userAgent.indexOf('Trident') > -1;
    var L = this.options.sliderL + this.options.sliderR * 2 + 3; // 滑块实际边长
    var drawImg = function (ctx, operation) {
        var l = that.options.sliderL;
        var r = that.options.sliderR;
        var PI = that.options.PI;
        var x = that.x;
        var y = that.y;
        ctx.beginPath();
        ctx.moveTo(x, y);
        ctx.arc(x + l / 2, y - r + 2, r, 0.72 * PI, 2.26 * PI);
        ctx.lineTo(x + l, y);
        ctx.arc(x + l + r - 2, y + l / 2, r, 1.21 * PI, 2.78 * PI);
        ctx.lineTo(x + l, y + l);
        ctx.lineTo(x, y + l);
        ctx.arc(x + r - 2, y + l / 2, r + 0.4, 2.76 * PI, 1.24 * PI, true);
        ctx.lineTo(x, y);
        ctx.lineWidth = 2;
        ctx.fillStyle = 'rgba(255, 255, 255, 0.7)';
        ctx.strokeStyle = 'rgba(255, 255, 255, 0.7)';
        ctx.stroke();
        ctx[operation]();
        ctx.globalCompositeOperation = isIE ? 'xor' : 'destination-over';
    };

    var getRandomNumberByRange = function (start, end) {
        return Math.round(Math.random() * (end - start) + start);
    };
    var img = new Image();
    img.crossOrigin = "Anonymous";
    var loadCount = 0;
    img.onload = function () {
        // 随机创建滑块的位置
        that.x = getRandomNumberByRange(L + 10, that.options.width - (L + 10));
        that.y = getRandomNumberByRange(10 + that.options.sliderR * 2, that.options.height - (L + 10));
        drawImg(that.canvasCtx, 'fill');
        drawImg(that.blockCtx, 'clip');

        that.canvasCtx.drawImage(img, 0, 0, that.options.width - 2, that.options.height);
        that.blockCtx.drawImage(img, 0, 0, that.options.width - 2, that.options.height);
        var y = that.y - that.options.sliderR * 2 - 1;
        var ImageData = that.blockCtx.getImageData(that.x - 3, y, L, L);
        that.block.width = L;
        that.blockCtx.putImageData(ImageData, 0, y + 1);
        that.text.text(that.text.attr('data-text'));
    };
    img.onerror = function () {
        loadCount++;
        if (window.location.protocol === 'file:') {
            loadCount = that.options.maxLoadCount;
            console.error("can't load pic resource file from File protocal. Please try http or https");
        }
        if (loadCount >= that.options.maxLoadCount) {
            that.text.text('加载失败').addClass('text-danger');
            return;
        }
        img.src = that.options.localImages();
    };
    img.setSrc = function () {
        var src = '';
        loadCount = 0;
        that.text.removeClass('text-danger');
        if ($.isFunction(that.options.setSrc)) src = that.options.setSrc();
        if (!src || src === '') src = 'https://picsum.photos/' + that.options.width + '/' + that.options.height + '/?image=' + Math.round(Math.random() * 20);
        if (isIE) { // IE浏览器无法通过img.crossOrigin跨域,使用ajax获取图片blob然后转为dataURL显示
            var xhr = new XMLHttpRequest();
            xhr.onloadend = function (e) {
                var file = new FileReader(); // FileReader仅支持IE10+
                file.readAsDataURL(e.target.response);
                file.onloadend = function (e) {
                    img.src = e.target.result;
                };
            };
            xhr.open('GET', src);
            xhr.responseType = 'blob';
            xhr.send();
        } else img.src = src;
    };
    img.setSrc();
    this.text.attr('data-text', this.options.barText);
    this.text.text(this.options.loadingText);
    this.img = img;
};

_proto.clean = function () {
    this.canvasCtx.clearRect(0, 0, this.options.width, this.options.height);
    this.blockCtx.clearRect(0, 0, this.options.width, this.options.height);
    this.block.width = this.options.width;
};

_proto.bindEvents = function () {
    var that = this;
    this.$element.on('selectstart', function () {
        return false;
    });

    $(this.refreshIcon).on('click', function () {
        that.text.text(that.options.barText);
        that.reset();
        if ($.isFunction(that.options.onRefresh)) that.options.onRefresh.call(that.$element);
    });

    var originX, originY, trail = [],
        isMouseDown = false;

    var handleDragStart = function (e) {
        if (that.text.hasClass('text-danger')) return;
        originX = e.clientX || e.touches[0].clientX;
        originY = e.clientY || e.touches[0].clientY;
        isMouseDown = true;
    };

    var handleDragMove = function (e) {
        if (!isMouseDown) return false;
        var eventX = e.clientX || e.touches[0].clientX;
        var eventY = e.clientY || e.touches[0].clientY;
        var moveX = eventX - originX;
        var moveY = eventY - originY;
        if (moveX < 0 || moveX + 40 > that.options.width) return false;
        that.slider.style.left = (moveX - 1) + 'px';
        var blockLeft = (that.options.width - 40 - 20) / (that.options.width - 40) * moveX;
        that.block.style.left = blockLeft + 'px';

        that.sliderContainer.addClass('sliderContainer_active');
        that.sliderMask.style.width = (moveX + 4) + 'px';
        trail.push(Math.round(moveY));
    };

    var handleDragEnd = function (e) {
        if (!isMouseDown) return false;
        isMouseDown = false;
        var eventX = e.clientX || e.changedTouches[0].clientX;
        if (eventX === originX) return false;
        that.sliderContainer.removeClass('sliderContainer_active');
        that.trail = trail;
        var data = that.verify();
        if (data.spliced && data.verified) {
            that.sliderContainer.addClass('sliderContainer_success');
            if ($.isFunction(that.options.onSuccess)) that.options.onSuccess.call(that.$element);
        } else {
            that.sliderContainer.addClass('sliderContainer_fail');
            if ($.isFunction(that.options.onFail)) that.options.onFail.call(that.$element);
            setTimeout(function () {
                that.text.text(that.options.failedText);
                that.reset();
            }, 1000);
        }
    };

    this.slider.addEventListener('mousedown', handleDragStart);
    this.slider.addEventListener('touchstart', handleDragStart);
    document.addEventListener('mousemove', handleDragMove);
    document.addEventListener('touchmove', handleDragMove);
    document.addEventListener('mouseup', handleDragEnd);
    document.addEventListener('touchend', handleDragEnd);

    document.addEventListener('mousedown', function () { return false; });
    document.addEventListener('touchstart', function () { return false; });
    document.addEventListener('swipe', function () { return false; });
};

_proto.verify = function () {
    var arr = this.trail; // 拖动时y轴的移动距离
    var left = parseInt(this.block.style.left);
    var verified = false;
    if (this.options.remoteUrl !== null) {
        verified = this.options.verify(arr, this.options.remoteUrl);
    }
    else {
        var sum = function (x, y) { return x + y; };
        var square = function (x) { return x * x; };
        var average = arr.reduce(sum) / arr.length;
        var deviations = arr.map(function (x) { return x - average; });
        var stddev = Math.sqrt(deviations.map(square).reduce(sum) / arr.length);
        verified = stddev !== 0;
    }
    return {
        spliced: Math.abs(left - this.x) < this.options.offset,
        verified: verified
    };
};

_proto.reset = function () {
    this.sliderContainer.removeClass('sliderContainer_fail sliderContainer_success');
    this.slider.style.left = 0;
    this.block.style.left = 0;
    this.sliderMask.style.width = 0;
    this.clean();
    this.text.attr('data-text', this.text.text());
    this.text.text(this.options.loadingText);
    this.img.setSrc();
};

mounted中初始化js对象

mounted() {
    // 滑动验证码 starts
    let self = this,
      CodeToken = '';
    $("#captcha").sliderCaptcha({
      repeatIcon: "ivu-icon ivu-icon-ios-refresh-empty iconStyle",
      setSrc: function () {
        return (
          "https:imgs/Pic" +
          Math.round(Math.random() * 136) +
          ".jpg"
        );
      },
      remoteUrl: basepath + "Verify",
      onSuccess: function () {
        var sended = self.sendTelVerificationCode(
          {
            verificationCodeToken: verificationCodeToken
          }
        );
        $(".captcha-layer").hide();
      },
      verify: function (arr, url) {
        var ret = false;
        var sendInfo = {
          telephone: self.userPhone,
          datas: arr,
        };
        $.ajax({
          url: url,
          data: JSON.stringify(sendInfo),
          async: false,
          cache: false,
          type: "POST",
          contentType: "application/json",
          dataType: "json",
          success: function (result) {
            CodeToken = result.verificationCodeToken;
            ret = result != "";
          },
        });
        return ret;
      },
    });
    // 滑动验证码 end
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值