Skip to the content.

package dependencies

"dependencies": {
  "react": "^17.0.1",
  ...
}

验证码组件

./Identify.js

import { useEffect } from 'react'

function Main({
  identifyCode = '1234', // 默认注册码
  fontSizeMin = 25, // 字体最小值
  fontSizeMax = 35, // 字体最大值
  backgroundColorMin = 200, // 验证码图片背景色最小值
  backgroundColorMax = 220, // 验证码图片背景色最大值
  dotColorMin = 60, // 背景干扰点最小值
  dotColorMax = 120, // 背景干扰点最大值
  contentWidth = 116, // 容器宽度
  contentHeight = 38, // 容器高度
  onClick,
}) {

  /**
   * 生成一个随机数
   * @param {*} min 
   * @param {*} max 
   */
  function randomNum(min, max) {
    return Math.floor(Math.random() * (max - min) + min)
  }

  /**
   * 生成一个随机的颜色
   * @param {*} min 
   * @param {*} max 
   */
  function randomColor(min, max) {
    let r = randomNum(min, max)
    let g = randomNum(min, max)
    let b = randomNum(min, max)
    return `rgb(${r},${g},${b})`
  }

  /**
   * 绘制画布
   */
  function drawPic() {
    let canvas = document.getElementById("s-canvas")
    let ctx = canvas.getContext("2d")
    ctx.textBaseline = "bottom"
    // 绘制背景
    ctx.fillStyle = randomColor(backgroundColorMin, backgroundColorMax)
    ctx.fillRect(0, 0, contentWidth, contentHeight)
    // 绘制文字
    for (let i = 0; i < identifyCode.length; i++) {
      drawText(ctx, identifyCode[i], i)
    }
    drawLine(ctx)
    drawDot(ctx)
  }

  /**
   * 生成字符
   * @param {*} ctx 
   * @param {*} txt 
   * @param {*} i 
   */
  function drawText(ctx, txt, i) {
    ctx.fillStyle = randomColor(50, 160) // 随机生成字体颜色
    ctx.font = randomNum(fontSizeMin, fontSizeMax) + "px SimHei" // 随机生成字体大小
    let x = (i + 1) * (contentWidth / (identifyCode.length + 1))
    let y = randomNum(fontSizeMax, contentHeight - 5)
    const deg = randomNum(-30, 30)
    // 修改坐标原点和旋转角度
    ctx.translate(x, y)
    ctx.rotate((deg * Math.PI) / 180)
    ctx.fillText(txt, 0, 0)
    // 恢复坐标原点和旋转角度
    ctx.rotate((-deg * Math.PI) / 180)
    ctx.translate(-x, -y)
  }

  /**
   * 绘制干扰线
   * @param {*} ctx 
   */
  function drawLine(ctx) {
    for (let i = 0; i < 4; i++) {
      ctx.strokeStyle = randomColor(100, 200)
      ctx.beginPath()
      ctx.moveTo(
        randomNum(0, contentWidth),
        randomNum(0, contentHeight)
      )
      ctx.lineTo(
        randomNum(0, contentWidth),
        randomNum(0, contentHeight)
      )
      ctx.stroke()
    }
  }

  /**
   * 绘制干扰点
   * @param {*} ctx 
   */
  function drawDot(ctx) {
    for (let i = 0; i < 30; i++) {
      ctx.fillStyle = randomColor(0, 255)
      ctx.beginPath()
      ctx.arc(
        randomNum(0, contentWidth),
        randomNum(0, contentHeight),
        1,
        0,
        2 * Math.PI
      )
      ctx.fill()
    }
  }

  useEffect(() => {
    drawPic()
    // eslint-disable-next-line
  }, [identifyCode])

  return (
    <canvas id='s-canvas' width={contentWidth} height={contentHeight} onClick={onClick} />
  )
}

export default Main

登录引用

这里使用简化后的demo代替antd校验组件,实际生产环境可根据业务需要修改 ./SignIn.js

import { useState, useEffect } from 'react'
import Identify from './Identify'


function Main() {
  const [identifyCode, setIdentifyCode] = useState('')
    , identifyCodeRange = '1234567890'

  /**
   * 点击验证码刷新验证码
   */
  function changeCode() {
    setIdentifyCode('')
    makeCode(identifyCodeRange, 4)
  }

  /**
   * 生成一个随机整数  randomNum(0, 10) 0 到 10 的随机整数, 包含 0 和 10
   * @param {Number} min 
   * @param {Number} max 
   */
  function randomNum(min, max) {
    max = max + 1
    return Math.floor(Math.random() * (max - min) + min)
  }

  /**
   * 随机生成验证码字符串
   * @param {String} data 随机字符池
   * @param {Number} len 字符长度
   */
  function makeCode(data, len) {
    let _str = ''
    for (let i = 0; i < len; i++) {
      _str += data[randomNum(0, data.length - 1)]
    }
    setIdentifyCode(_str)
  }

  /**
   * 登录验证通过
   */
  function submitHandle() {
    makeCode(identifyCodeRange, 4) // 登录验证通过马上重置节流
    console.log('登录成功')
  }

  useEffect(() => {
    makeCode(identifyCodeRange, 4)
    // eslint-disable-next-line
  }, [])

  return <form>
    <input placeholder='username'/>
    <input placeholder='password'/>
    <input placeholder='captcha'/>
    <Identify identifyCode={identifyCode} contentWidth={240} onClick={changeCode} />
    <button onClick={submitHandle}>Sign in</button>
  </form>
}

export default Main