滑块验证参考 https://www.jianshu.com/p/341843516639
https://github.com/menthe/unlock.js
https://blog.csdn.net/tel13259437538/article/details/79823112
https://blog.csdn.net/tel13259437538/article/details/79822694
图片验证码参考 https://segmentfault.com/a/1190000018309458
rc-slider-captcha
https://github.com/caijf/rc-slider-captcha
https://juejin.cn/post/7160519128950767652
pnpm add rc-slider-captcha
支持图片验证,滑块验证
SliderBlock
import React, {useEffect, useRef, useState, memo} from 'react';
import PropTypes from 'prop-types';
SliderBlock.propTypes = {
onChange: PropTypes.func.isRequired,
height: PropTypes.number,
};
SliderBlock.defaultProps = {
height: 32,
onChange: () => {},
}
function SliderBlock({height, onChange}) {
const btnRef = useRef();
const [title, setTitle] = useState('拖动滑块验证');
const style = {height}
useEffect(init, []);
function init() {
const $slider = btnRef.current;
if (!$slider) return console.error('没有找到 _slider_ DOM');
const $btn = $slider.querySelector('.button') // 滑块
const $title = $slider.querySelector('.title') // 文字
const $bg = $slider.querySelector('.success') // 背景颜色
const MOVE_WIDTH = $slider.offsetWidth - $btn.offsetWidth; // 可以移动的距离
// 触发事件 onmousedown按下 onmousemove移动 onmouseup松开
$btn.onmousedown = (e) => {
// e.clientX 鼠标点的位置
onMouseMove(e.clientX)
}
// 鼠标松开时
document.onmouseup = () => {
if (parseInt($btn.style.left) === MOVE_WIDTH) return;
// 松开后回到原点,清除移动事件
$btn.style.left = 0
$bg.style.width = 0
document.onmousemove = null
$title.classList.remove('white')
}
// 拖拽移动时发生
function onMouseMove(clientX) {
document.onmousemove = (e) => {
e.preventDefault();
// 移动的X轴坐标 = 当前的 clientX - 之前鼠标的 clientX
const moveX = e.clientX - clientX;
// 可移动的范围 = 总宽度 - 按钮的宽度
if (moveX >= 0 && moveX <= MOVE_WIDTH) {
$btn.style.left = moveX + 'px' // 滑块绝对定位
$bg.style.width = moveX + 'px' // 设备背景的宽度
if (moveX > MOVE_WIDTH / 2) {
$title.classList.add('white')
}
}
// 验证成功
if (moveX >= MOVE_WIDTH) {
$btn.style.left = MOVE_WIDTH + 'px' // 滑块绝对定位
$bg.style.width = MOVE_WIDTH + 'px' // 设备背景的宽度
setTitle('验证成功')
onChange(true)
// 事件清除-按下、移动
$btn.onmousedown = null
$btn.onmouseup = null
document.onmousemove = null
}
}
}
}
return (
<div
className="_slider_"
ref={btnRef}
style={style}
>
<div className="button"/>
<span className="title">{title}</span>
<span className="success"/>
</div>
);
}
export default memo(SliderBlock);
slider-block.less
.white {
color: #fff;
transition: color 0.3s linear;
}
._slider_ {
display: flex;
align-items: center;
position: relative;
width: 100%;
height: 32px;
background: #fafafa;
user-select:none;
.button {
position: absolute;
left: 0;
top: 0;
width: 40px;
height: 100%;
border: 1px solid #dedede;
color: rgba(0, 0, 0, 0.65);
user-select:none;
will-change: left;
z-index: 9;
background: #fafafa url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA3hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDIxIDc5LjE1NTc3MiwgMjAxNC8wMS8xMy0xOTo0NDowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo0ZDhlNWY5My05NmI0LTRlNWQtOGFjYi03ZTY4OGYyMTU2ZTYiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NTEyNTVEMURGMkVFMTFFNEI5NDBCMjQ2M0ExMDQ1OUYiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NTEyNTVEMUNGMkVFMTFFNEI5NDBCMjQ2M0ExMDQ1OUYiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTQgKE1hY2ludG9zaCkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo2MTc5NzNmZS02OTQxLTQyOTYtYTIwNi02NDI2YTNkOWU5YmUiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6NGQ4ZTVmOTMtOTZiNC00ZTVkLThhY2ItN2U2ODhmMjE1NmU2Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+YiRG4AAAALFJREFUeNpi/P//PwMlgImBQkA9A+bOnfsIiBOxKcInh+yCaCDuByoswaIOpxwjciACFegBqZ1AvBSIS5OTk/8TkmNEjwWgQiUgtQuIjwAxUF3yX3xyGIEIFLwHpKyAWB+I1xGSwxULIGf9A7mQkBwTlhBXAFLHgPgqEAcTkmNCU6AL9d8WII4HOvk3ITkWJAXWUMlOoGQHmsE45ViQ2KuBuASoYC4Wf+OUYxz6mQkgwAAN9mIrUReCXgAAAABJRU5ErkJggg==) center no-repeat;
&:hover {
cursor: move;
}
}
.title {
position: absolute;
left: 50%;
transform: translateX(-50%);
background-color: transparent;
z-index: 2;
}
.success {
position: absolute;
height: 100%;
background-color: #1e8e3e;
z-index: 1;
}
}