前端 React 弹窗式 滑动验证码实现

发布于:2025-04-16 ⋅ 阅读:(25) ⋅ 点赞:(0)

目录

一、安装依赖

1、rc-slider-captcha

2、create-puzzle

二、个人封装好的组件拿去用

三、效果展示


一、安装依赖

这里需要引入两个依赖,若有后端图片接入,可以不引入第二个依赖

1、rc-slider-captcha

滑动验证码生成的库

国内网:rc-slider-captcha - npm

外网演示:https://caijf.github.io/rc-slider-captcha

yarn add rc-slider-captcha
2、create-puzzle

这个库可以让图片生成拼图

地址:create-puzzle - npm

yarn add create-puzzle

二、个人封装好的组件拿去用

注意:引入的图片尺寸需要对应,否则可能出现比例问题。

280 x 173

/**
 * @author: Dragon Wu
 * @since: 2025/4/10 17:40
 * @description: 弹窗显示滑动验证码
 */

import React, {useRef} from "react";
import SliderCaptcha from "rc-slider-captcha";
import {Modal} from "antd";
// 引入生成拼图的库
import createPuzzle from "create-puzzle";

export type Result = {
    bgUrl: string;          // 背景图
    puzzleUrl: string;      // 拼图
    x?: number;              // x 轴偏移值。如果使用该值校验,建议前后阈值增减 5 的范围
    y?: number;             // y 轴偏移值,等高拼图时值始终为 0
};

const ModalSliderCaptcha: React.FC<{
    open: boolean,                                  // 是否打开
    onCancel: () => void,                           // 关闭时调用
    range?: number,                                 // 误差范围
    format?: "dataURL" | "blob",                    // 拼图库format类型,默认dataURL即base64格式
    onVerify?: (data?: Result) => void | boolean    // 是否校验成功。非后端验证模式下,data存在代表成功,data为空代表失败
    request?: () => Promise<undefined | Result>     // 请求后端验证码参数
    modalProps?: {},                                // Modal组件的属性,见:https://ant.design/components/modal-cn#api
    sliderCaptchaProps?: {},                        // SliderCaptcha的属性,详情见:https://www.npmjs.com/package/rc-slider-captcha
}> = React.memo(({
                     modalProps, sliderCaptchaProps, open, onCancel,
                     format = "dataURL", range = 5, onVerify, request
                 }) => {

    const offsetXRef = useRef(0)    // x 轴偏移值
    const handleOffsetX = (res?: Result) => {
        offsetXRef.current = res?.x ?? 0

        return {
            bgUrl: res?.bgUrl,
            puzzleUrl: res?.puzzleUrl
        }
    }

    const requestCaptcha = async () => {
        if (request) {
            return request().then(handleOffsetX)
        } else {
            return createPuzzle("/assets/img/source/captcha-bg.png", {
                format,
                width: 60,
                height: 60,
                bgWidth: 280,
                bgHeight: 173,
                quality: 1.0,       // 图片质量,默认0.8
            }).then(handleOffsetX)
        }
    }
    const onVerifyCaptcha = (data?: Result) => {
        if (request) {
            // 后端验证码模式下
            if (onVerify) {
                if (onVerify(data)) {
                    // 后端校验通过,验证成功
                    return Promise.resolve()
                }
            }
        } else {
            // 非后端验证模式下
            if (data?.x && data?.x >= offsetXRef.current - range && data?.x < offsetXRef.current + range) {
                if (onVerify) {
                    onVerify(data)
                }
                return Promise.resolve()
            }
            if (onVerify) {
                onVerify()
            }
        }
        return Promise.reject()
    }

    return (
        <Modal {...{
            title: "安全验证",
            zIndex: 1024,
            style: {
                maxWidth: "100%",
            },
            styles: {
                content: {
                    padding: 20
                }
            },
            centered: true,
            width: 320,
            footer: false,
            ...modalProps
        }}
               onCancel={onCancel}
               open={open}>
            <SliderCaptcha request={requestCaptcha as any}
                           onVerify={onVerifyCaptcha as any}
                           bgSize={{
                               width: 280,
                               height: 173
                           }}
                           tipText={{
                               default: "向右👉拖动完成拼图",
                               loading: "👩🏻‍💻🧑‍💻努力中...",
                           }}
                           style={{
                               "--rcsc-primary": "#6153FC",
                               "--rcsc-primary-light": "#efecfc",
                           }}
                           loadingDelay={300}
                           {...sliderCaptchaProps}
            />
        </Modal>
    )
});

ModalSliderCaptcha.displayName = "ModalSliderCaptcha";

export default ModalSliderCaptcha;

三、效果展示

将组件放在自己的其他组件上,通过Antd Modal的open属性来控制开关,点击按钮实现弹窗滑块验证码功能。后续,将加入如何用SpringBoot来实现滑块验证码图片生成,以完成前后端滑动验证码功能。

前端部分总结到此!


网站公告

今日签到

点亮在社区的每一天
去签到