图片验证码

329 阅读1分钟

react + antd

代码

Login/Components/VerificationCode

import React, { FC, useEffect, useState } from 'react';
import { Tooltip } from 'antd';
import { randomNum } from '@/hooks';
export const VerificationCode: FC<{ onChange: Function }> = (props) => {
    const [change, setChange] = useState(false);
    const { onChange } = props;
    useEffect(() => {
        const canvas = document.getElementById('code') as HTMLCanvasElement;
        const ctx = canvas?.getContext('2d');
        /* 清空画布*/
        ctx?.clearRect(0, 0, canvas.width, canvas.height);
        let code = '';
        /*绘制4位验证码*/
        for (let i = 4; i > 0; i--) {
            const num = randomNum(0, 9) + '';
            /**设置每个验证码的x,y坐标和旋转角度 */
            const x = (canvas.width / 5) * i + randomNum(-10, 10);
            const y = randomNum(35, 45);
            const r = (randomNum(-30, 30) * Math.PI) / 180;
            code = num + code;
            // 先定原点再旋转
            ctx?.translate(x, y);
            ctx?.rotate(r);
            // fillStyle设置验证码样式,fillText绘制验证码
            ctx!.fillStyle = 
            `rgba(${randomNum(10, 50)},${randomNum(10, 50)},${randomNum(10,50)},0.6)`;
            ctx!.font = `${randomNum(30, 40)}px Arial`;
            ctx!.shadowOffsetX = 3;
            ctx!.shadowOffsetY = 3;
            ctx!.shadowBlur = 3;
            ctx!.shadowColor = 'rgba(0,0,0,0.5)';
            ctx?.fillText(num, 0, 0);
            // 设置完一位验证码后,撤销位移和旋转设置
            ctx?.rotate(-r);
            ctx?.translate(-x, -y);
        }
        /**绘制干扰线和干扰点 */
        ctx?.beginPath();
        for (let i = 0; i < randomNum(2, 4); i++) {
            /*确定干扰线起点和终点坐标*/
            const startX = randomNum(0, canvas.width / 2);
            const startY = randomNum(0, canvas.height);

            const endX = randomNum(canvas.width / 2, canvas.width);
            const endY = randomNum(0, canvas.height);

            /*使用stroke方法绘制干扰线*/
            ctx!.strokeStyle = 
            `rgba(${randomNum(100, 130)},${randomNum(100, 130)},${randomNum(100,130)},
            ${randomNum(0.3, 0.6)})`;
            ctx?.moveTo(startX, startY);
            ctx?.lineTo(endX, endY);
            ctx?.stroke();
        }
        for (let i = 0; i < randomNum(10, 20); i++) {
            /*确定干扰点坐标*/
            let x = randomNum(0, canvas.width);
            let y = randomNum(0, canvas.height);

            /*使用fill方法绘制干扰点,注意干扰点要使用填充方式*/
            ctx!.fillStyle = `rgba(${randomNum(100, 130)},${randomNum(100, 130)},${randomNum(
                100,
                130
            )},${randomNum(0.3, 0.9)})`;
            ctx?.moveTo(x, y);
            /*通过arc方法绘制坐标为(0,0,),半径为1,起点角度为0度,终点角度为360度的圆形黑点(干扰点)*/
            ctx?.arc(x, y, 1, 0, 2 * Math.PI, false);
            ctx?.fill();
        }
        onChange(code);
    }, [change]);
    return (
        <Tooltip title="点击切换">
            <canvas
                id="code"
                width="220"
                height="50"
                onClick={() => setChange((state) => !state)}
            ></canvas>
        </Tooltip>
    );
};

hooks/index.ts

export const randomNum=(minNum:number,maxNum:number)
=>Math.floor(Math.random()*(maxNum-minNum+1))+minNum

Login/index.tsx

import React, { FC, useState } from 'react';
import { Button, Checkbox, Form, Input, Space } from 'antd';
import { VerificationCode } from './Components';
const Login: FC = () => {
    const [code, setCode] = useState('');
    const onFinish = (values: any) => {
        // do something
    };
    return (
           <Form
                name="normal_login"
                onFinish={onFinish}
                size="large"
            >
              <Form.Item
                    name="password"
                    rules={[{ required: true, message: 'Please input your Password!' }]}
                >
                    <Input.Password
                        type="password"
                        placeholder="Password"/>
                </Form.Item>
                <Form.Item
                    name="code"
                    rules={[
                        {
                            required: true,
                            message: 'Please input your verification code!',
                        },
                        {
                            pattern: new RegExp(code),

                            message: 'Wrong verification code!',
                        },
                    ]}
                    hasFeedback
                >
                    <Space>
                        <VerificationCode onChange={(num: any) => setCode(num)} />
                        <Input placeholder="请输入验证码" />
                    </Space>
                </Form.Item>
                <Form.Item>
                    <Button type="primary" htmlType="submit">
                        Log in
                    </Button>
                </Form.Item>
            </Form>
             
}

参考资料