This commit is contained in:
nanguaboss
2026-08-03 00:07:01 +08:00
commit 71c6e8d9c1
112 changed files with 7815 additions and 0 deletions
+120
View File
@@ -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);