Hanye官网
Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

useCaptcha.ts 3.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. import { ref, computed } from 'vue';
  2. /**
  3. * 生成随机字符串
  4. * @param length 字符串长度
  5. * @returns 随机字符串
  6. */
  7. function generateRandomString(length: number): string {
  8. const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
  9. let result = '';
  10. for (let i = 0; i < length; i++) {
  11. result += characters.charAt(Math.floor(Math.random() * characters.length));
  12. }
  13. return result;
  14. }
  15. /**
  16. * 为验证码文本生成扭曲的 SVG
  17. * @param text 验证码文本
  18. * @returns SVG 字符串
  19. */
  20. function generateCaptchaSvg(text: string): string {
  21. const width = 150;
  22. const height = 50;
  23. const fontSize = 30;
  24. const letters = text.split('');
  25. // 应用于整个 SVG 的滤镜,增加噪点和轻微扭曲
  26. const filter = `
  27. <filter id="captchaNoise">
  28. <feTurbulence baseFrequency="0.7 0.8" numOctaves="3" seed="${Math.random() * 100}" stitchTiles="stitch" type="fractalNoise" result="turbulence"/>
  29. <feDisplacementMap in="SourceGraphic" in2="turbulence" scale="3" xChannelSelector="R" yChannelSelector="G" result="displacement"/>
  30. <feGaussianBlur in="displacement" stdDeviation="0.5" />
  31. </filter>
  32. `;
  33. // 为每个字母生成 <text> 元素,并应用随机变换
  34. const textElements = letters.map((char, index) => {
  35. const x = (width / text.length) * (index + 0.5);
  36. const y = height / 2 + fontSize / 3; // 基线调整
  37. const rotate = Math.random() * 30 - 15; // -15 到 15 度旋转
  38. const skewX = Math.random() * 10 - 5; // 轻微倾斜
  39. const fill = `hsl(${Math.random() * 360}, 70%, 70%)`; // 随机 HSL 颜色
  40. return `<text
  41. x="${x}"
  42. y="${y}"
  43. font-size="${fontSize}"
  44. font-family="Arial, sans-serif"
  45. font-weight="bold"
  46. text-anchor="middle"
  47. fill="${fill}"
  48. transform="rotate(${rotate} ${x} ${y}) skewX(${skewX})"
  49. style="letter-spacing: 1px;"
  50. >${char}</text>`;
  51. }).join('');
  52. // 添加几条干扰线
  53. let lines = '';
  54. for (let i = 0; i < 3; i++) {
  55. lines += `<line
  56. x1="${Math.random() * width * 0.8}"
  57. y1="${Math.random() * height}"
  58. x2="${Math.random() * width * 0.8 + width * 0.2}"
  59. y2="${Math.random() * height}"
  60. stroke="rgba(180, 180, 200, 0.3)"
  61. stroke-width="2"
  62. />`;
  63. }
  64. return `
  65. <svg
  66. xmlns="http://www.w3.org/2000/svg"
  67. width="${width}"
  68. height="${height}"
  69. viewBox="0 0 ${width} ${height}"
  70. style="background-color: rgba(55, 65, 81, 0.3); border-radius: 6px; border: 1px solid rgba(107, 114, 128, 0.5);"
  71. >
  72. <defs>
  73. ${filter}
  74. </defs>
  75. <g style="filter: url(#captchaNoise);">
  76. ${textElements}
  77. ${lines}
  78. </g>
  79. </svg>
  80. `;
  81. }
  82. export function useCaptcha(length: number = 5) {
  83. const captchaText = ref('');
  84. const userInput = ref('');
  85. const captchaSvg = ref('');
  86. const error = ref('');
  87. /**
  88. * 生成新的验证码
  89. */
  90. const generateCaptcha = () => {
  91. const newText = generateRandomString(length);
  92. captchaText.value = newText;
  93. captchaSvg.value = generateCaptchaSvg(newText);
  94. userInput.value = ''; // 清空用户输入
  95. error.value = ''; // 清除错误
  96. };
  97. /**
  98. * 验证用户输入
  99. * @returns 是否验证通过
  100. */
  101. const validateCaptcha = (): boolean => {
  102. if (!userInput.value) {
  103. error.value = '请输入验证码';
  104. return false;
  105. }
  106. if (userInput.value.toLowerCase() !== captchaText.value.toLowerCase()) {
  107. error.value = '验证码错误';
  108. generateCaptcha(); // 错误后自动刷新
  109. return false;
  110. }
  111. error.value = '';
  112. return true;
  113. };
  114. // 初始化生成第一个验证码
  115. generateCaptcha();
  116. return {
  117. userInput,
  118. captchaSvg,
  119. error,
  120. generateCaptcha,
  121. validateCaptcha,
  122. };
  123. }