JavaScript

超轻量级php框架startmvc

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

更新时间:2020-09-11 20:54:01 作者:startmvc
电脑和手机移动端都适用的jQuery拖动滑块图片拼图验证码插件,通过鼠标拖动或触屏滑动填

电脑和手机移动端都适用的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实现拖动滑块图片拼图验证码插件希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

jquery 拖动滑块验证码 jquery 滑块验证码