/** * slider.js - 滑块验证组件(纯前端实现) * 用法: *
* 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 = '
' + '
' + '
请按住滑块,拖动到最右边
' + '
⟶
' + '
'; 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);