v1.0.10
This commit is contained in:
File diff suppressed because one or more lines are too long
Vendored
+45
File diff suppressed because one or more lines are too long
Binary file not shown.
|
After Width: | Height: | Size: 2.6 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 6.5 KiB |
Vendored
+2
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
|
After Width: | Height: | Size: 5.7 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 701 B |
Binary file not shown.
|
After Width: | Height: | Size: 1.7 KiB |
@@ -0,0 +1,120 @@
|
||||
/**
|
||||
* slider.js - 滑块验证组件(纯前端实现)
|
||||
* 用法:
|
||||
* <div id="slider"></div>
|
||||
* var slider = new SliderVerify('#slider', function(token){ ... }); // 拖动成功回调
|
||||
* slider.reset(); // 重置
|
||||
* 说明:拖动到目标位置后生成 slider_token(含随机数+偏移校验和),
|
||||
* 提交登录时携带该 token;服务端校验 token 非空且长度合法。
|
||||
* 如需更高安全性,可后续改为服务端签发 token(接口生成背景图+缺口位置)。
|
||||
*/
|
||||
(function (window) {
|
||||
'use strict';
|
||||
|
||||
function SliderVerify(selector, onSuccess) {
|
||||
this.el = typeof selector === 'string' ? document.querySelector(selector) : selector;
|
||||
this.onSuccess = onSuccess || function () {};
|
||||
this.passed = false;
|
||||
this.init();
|
||||
}
|
||||
|
||||
SliderVerify.prototype.init = function () {
|
||||
var self = this;
|
||||
var html =
|
||||
'<div class="slider-box">' +
|
||||
' <div class="slider-bg"></div>' +
|
||||
' <div class="slider-text">请按住滑块,拖动到最右边</div>' +
|
||||
' <div class="slider-btn">⟶</div>' +
|
||||
'</div>';
|
||||
this.el.innerHTML = html;
|
||||
|
||||
this.box = this.el.querySelector('.slider-box');
|
||||
this.bg = this.el.querySelector('.slider-bg');
|
||||
this.text = this.el.querySelector('.slider-text');
|
||||
this.btn = this.el.querySelector('.slider-btn');
|
||||
|
||||
this.boxWidth = this.box.offsetWidth || 300;
|
||||
this.dragging = false;
|
||||
this.startX = 0;
|
||||
this.offset = 0;
|
||||
|
||||
this.btn.addEventListener('mousedown', function (e) { self.startDrag(e); });
|
||||
this.btn.addEventListener('touchstart', function (e) { self.startDrag(e.touches[0]); }, { passive: true });
|
||||
|
||||
document.addEventListener('mousemove', function (e) { self.moveDrag(e); });
|
||||
document.addEventListener('touchmove', function (e) { self.moveDrag(e.touches[0]); }, { passive: false });
|
||||
document.addEventListener('mouseup', function () { self.endDrag(); });
|
||||
document.addEventListener('touchend', function () { self.endDrag(); });
|
||||
};
|
||||
|
||||
SliderVerify.prototype.startDrag = function (e) {
|
||||
if (this.passed) return;
|
||||
e.preventDefault && e.preventDefault();
|
||||
this.dragging = true;
|
||||
this.startX = e.clientX;
|
||||
};
|
||||
|
||||
SliderVerify.prototype.moveDrag = function (e) {
|
||||
if (!this.dragging) return;
|
||||
e.preventDefault && e.preventDefault();
|
||||
var dx = e.clientX - this.startX;
|
||||
this.offset = Math.max(0, Math.min(dx, this.boxWidth - 50));
|
||||
this.btn.style.left = this.offset + 'px';
|
||||
this.bg.style.width = this.offset + 50 + 'px';
|
||||
if (this.offset >= this.boxWidth - 60) {
|
||||
this.endDrag(true);
|
||||
}
|
||||
};
|
||||
|
||||
SliderVerify.prototype.endDrag = function (force) {
|
||||
if (!this.dragging) return;
|
||||
this.dragging = false;
|
||||
|
||||
if (force || this.offset >= this.boxWidth - 60) {
|
||||
// 验证通过
|
||||
this.passed = true;
|
||||
this.btn.style.left = (this.boxWidth - 50) + 'px';
|
||||
this.bg.style.width = '100%';
|
||||
this.text.innerHTML = '✓ 验证通过';
|
||||
this.text.className = 'slider-text slider-success';
|
||||
|
||||
var token = this.makeToken();
|
||||
if (this.onSuccess) this.onSuccess(token);
|
||||
} else {
|
||||
// 复位
|
||||
var self = this;
|
||||
this.btn.style.transition = 'left .3s';
|
||||
this.bg.style.transition = 'width .3s';
|
||||
this.btn.style.left = '0px';
|
||||
this.bg.style.width = '50px';
|
||||
setTimeout(function () {
|
||||
self.btn.style.transition = '';
|
||||
self.bg.style.transition = '';
|
||||
}, 320);
|
||||
}
|
||||
};
|
||||
|
||||
/** 生成滑块 token:时间戳+随机数+偏移校验和 */
|
||||
SliderVerify.prototype.makeToken = function () {
|
||||
var rand = Math.random().toString(36).substr(2, 8);
|
||||
var ts = Date.now().toString(36);
|
||||
var offset = this.offset;
|
||||
var checksum = (offset * 7 + ts.length * 13).toString(36);
|
||||
return 'sl_' + ts + '_' + rand + '_' + checksum + '_' + offset;
|
||||
};
|
||||
|
||||
SliderVerify.prototype.reset = function () {
|
||||
this.passed = false;
|
||||
this.offset = 0;
|
||||
this.btn.style.left = '0px';
|
||||
this.bg.style.width = '50px';
|
||||
this.text.innerHTML = '请按住滑块,拖动到最右边';
|
||||
this.text.className = 'slider-text';
|
||||
};
|
||||
|
||||
SliderVerify.prototype.isPassed = function () {
|
||||
return this.passed;
|
||||
};
|
||||
|
||||
window.SliderVerify = SliderVerify;
|
||||
})(window);
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user