image.png

滑块验证参考 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

image.png

  1. import React, {useEffect, useRef, useState, memo} from 'react';
  2. import PropTypes from 'prop-types';
  3. SliderBlock.propTypes = {
  4. onChange: PropTypes.func.isRequired,
  5. height: PropTypes.number,
  6. };
  7. SliderBlock.defaultProps = {
  8. height: 32,
  9. onChange: () => {},
  10. }
  11. function SliderBlock({height, onChange}) {
  12. const btnRef = useRef();
  13. const [title, setTitle] = useState('拖动滑块验证');
  14. const style = {height}
  15. useEffect(init, []);
  16. function init() {
  17. const $slider = btnRef.current;
  18. if (!$slider) return console.error('没有找到 _slider_ DOM');
  19. const $btn = $slider.querySelector('.button') // 滑块
  20. const $title = $slider.querySelector('.title') // 文字
  21. const $bg = $slider.querySelector('.success') // 背景颜色
  22. const MOVE_WIDTH = $slider.offsetWidth - $btn.offsetWidth; // 可以移动的距离
  23. // 触发事件 onmousedown按下 onmousemove移动 onmouseup松开
  24. $btn.onmousedown = (e) => {
  25. // e.clientX 鼠标点的位置
  26. onMouseMove(e.clientX)
  27. }
  28. // 鼠标松开时
  29. document.onmouseup = () => {
  30. if (parseInt($btn.style.left) === MOVE_WIDTH) return;
  31. // 松开后回到原点,清除移动事件
  32. $btn.style.left = 0
  33. $bg.style.width = 0
  34. document.onmousemove = null
  35. $title.classList.remove('white')
  36. }
  37. // 拖拽移动时发生
  38. function onMouseMove(clientX) {
  39. document.onmousemove = (e) => {
  40. e.preventDefault();
  41. // 移动的X轴坐标 = 当前的 clientX - 之前鼠标的 clientX
  42. const moveX = e.clientX - clientX;
  43. // 可移动的范围 = 总宽度 - 按钮的宽度
  44. if (moveX >= 0 && moveX <= MOVE_WIDTH) {
  45. $btn.style.left = moveX + 'px' // 滑块绝对定位
  46. $bg.style.width = moveX + 'px' // 设备背景的宽度
  47. if (moveX > MOVE_WIDTH / 2) {
  48. $title.classList.add('white')
  49. }
  50. }
  51. // 验证成功
  52. if (moveX >= MOVE_WIDTH) {
  53. $btn.style.left = MOVE_WIDTH + 'px' // 滑块绝对定位
  54. $bg.style.width = MOVE_WIDTH + 'px' // 设备背景的宽度
  55. setTitle('验证成功')
  56. onChange(true)
  57. // 事件清除-按下、移动
  58. $btn.onmousedown = null
  59. $btn.onmouseup = null
  60. document.onmousemove = null
  61. }
  62. }
  63. }
  64. }
  65. return (
  66. <div
  67. className="_slider_"
  68. ref={btnRef}
  69. style={style}
  70. >
  71. <div className="button"/>
  72. <span className="title">{title}</span>
  73. <span className="success"/>
  74. </div>
  75. );
  76. }
  77. export default memo(SliderBlock);

slider-block.less

  1. .white {
  2. color: #fff;
  3. transition: color 0.3s linear;
  4. }
  5. ._slider_ {
  6. display: flex;
  7. align-items: center;
  8. position: relative;
  9. width: 100%;
  10. height: 32px;
  11. background: #fafafa;
  12. user-select:none;
  13. .button {
  14. position: absolute;
  15. left: 0;
  16. top: 0;
  17. width: 40px;
  18. height: 100%;
  19. border: 1px solid #dedede;
  20. color: rgba(0, 0, 0, 0.65);
  21. user-select:none;
  22. will-change: left;
  23. z-index: 9;
  24. 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;
  25. &:hover {
  26. cursor: move;
  27. }
  28. }
  29. .title {
  30. position: absolute;
  31. left: 50%;
  32. transform: translateX(-50%);
  33. background-color: transparent;
  34. z-index: 2;
  35. }
  36. .success {
  37. position: absolute;
  38. height: 100%;
  39. background-color: #1e8e3e;
  40. z-index: 1;
  41. }
  42. }

爬虫绕过验证码

https://zhuanlan.zhihu.com/p/76068795