首页 > 编程 > JavaScript > 正文

html+jQuery实现拖动滑块图片拼图验证码插件【移动端适用】

2019-11-19 10:50:29
字体:
来源:转载
供稿:网友

电脑和手机移动端都适用的jQuery拖动滑块图片拼图验证码插件,通过鼠标拖动或触屏滑动填充拼图来进行安全验证,点击刷新可以更换当前待验证的图片。

HTML & css:

<!DOCTYPE html><html lang="zh"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>拖动滑块图片拼图验证码插件</title><!--框架样式--><link href="css/bootstrap.min.css" rel="external nofollow" rel="stylesheet"><!--图标样式--><link href="https://cdn.bootcss.com/font-awesome/5.7.2/css/all.min.css" rel="stylesheet"><!--主要样式--><link href="disk/slidercaptcha.css" rel="external nofollow" rel="stylesheet" /><style>.slidercaptcha { margin: 0 auto; width: 314px; height: 286px; border-radius: 4px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.125); margin-top: 40px;}.slidercaptcha .card-body { padding: 1rem;}.slidercaptcha canvas:first-child { border-radius: 4px; border: 1px solid #e6e8eb;}.slidercaptcha.card .card-header { background-image: none; background-color: rgba(0, 0, 0, 0.03);}.refreshIcon { top: -54px;}</style></head><body><div class="container-fluid"> <div class="form-row"> <div class="col-12"> <div class="slidercaptcha card"> <div class="card-header">  <span>请完成安全验证</span> </div> <div class="card-body"><div id="captcha"></div></div> </div> </div> </div></div><script src="js/jquery-1.11.0.min.js" type="text/javascript"></script><script src="disk/longbow.slidercaptcha.js"></script><script> $('#captcha').sliderCaptcha({ repeatIcon: 'fa fa-redo', setSrc: function () { return 'http://images.sdgxgz.com/Pic' + Math.round(Math.random() * 136) + '.jpg'; }, onSuccess: function () { alert('验证通过!'); } });</script></body></html>disk/slidercaptcha.css:body { overflow-x: hidden;}.block { position: absolute; left: 0; top: 0;}.sliderContainer { position: relative; text-align: center; line-height: 40px; background: #f7f9fa; color: #45494c; border-radius: 2px;}.sliderbg { position: absolute; left: 0; right: 0; top: 0; background-color: #f7f9fa; height: 40px; border-radius: 2px; border: 1px solid #e6e8eb;}.sliderContainer_active .slider { top: -1px; border: 1px solid #1991FA;}.sliderContainer_active .sliderMask { border-width: 1px 0 1px 1px;}.sliderContainer_success .slider { top: -1px; border: 1px solid #52CCBA; background-color: #52CCBA !important;}.sliderContainer_success .sliderMask { border: 1px solid #52CCBA; border-width: 1px 0 1px 1px; background-color: #D2F4EF;}.sliderContainer_success .sliderIcon:before { content: "/f00c";}.sliderContainer_fail .slider { top: -1px; border: 1px solid #f57a7a; background-color: #f57a7a !important;}.sliderContainer_fail .sliderMask { border: 1px solid #f57a7a; background-color: #fce1e1; border-width: 1px 0 1px 1px;}.sliderContainer_fail .sliderIcon:before { content: "/f00d";}.sliderContainer_active .sliderText, .sliderContainer_success .sliderText, .sliderContainer_fail .sliderText { display: none;}.sliderMask { position: absolute; left: 0; top: 0; height: 40px; border: 0 solid #1991FA; background: #D1E9FE; border-radius: 2px;}.slider { position: absolute; top: 0; left: 0; width: 40px; height: 40px; background: #fff; box-shadow: 0 0 3px rgba(0, 0, 0, 0.3); cursor: pointer; transition: background .2s linear; border-radius: 2px; display: flex; align-items: center; justify-content: center;}.slider:hover { background: #1991FA;}.slider:hover .sliderIcon { background-position: 0 -13px;}.sliderText { position: relative;}.sliderIcon {}.refreshIcon { position: absolute; right: 0; top: 0; cursor: pointer; margin: 6px; color: rgba(0,0,0,.25); font-size: 1rem; z-index: 5; transition: color .3s linear;} .refreshIcon:hover { color: #6c757d; }disk/longbow.slidercaptcha.js:(function ($) { 'use strict'; var 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(); }; 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: 'fa fa-repeat',  maxLoadCount: 3,  localImages: function () {   return 'images/Pic' + Math.round(Math.random() * 4) + '.jpg';  } }; 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', 'refreshIcon ' + 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));  Object.assign(this, {   canvas,   block,   sliderContainer: $(sliderContainer),   refreshIcon,   slider,   sliderMask,   sliderIcon,   text: $(text),   canvasCtx: canvas.getContext('2d'),   blockCtx: block.getContext('2d')  }) }; _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' : 'overlay'  }  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);   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(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 {    spliced,    verified   } = that.verify()   if (spliced && 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(() => {     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; }); }; _proto.verify = function () {  var sum = function (x, y) { return x + y; };  var square = function (x) { return x * x; };  var arr = this.trail // 拖动时y轴的移动距离  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);  var left = parseInt(this.block.style.left);  return {   spliced: Math.abs(left - this.x) < this.options.offset,   verified: stddev !== 0, // 简单验证下拖动轨迹,为零时表示Y轴上下没有波动,可能非人为操作  } }; _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(); };})(jQuery);

附录1:需要注意css和js的引用路径;

总结

以上所述是小编给大家介绍的html+jQuery实现拖动滑块图片拼图验证码插件希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对武林网网站的支持!如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表