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

目录

一、安装依赖

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

javascript 复制代码
/**
 * @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来实现滑块验证码图片生成,以完成前后端滑动验证码功能。

前端部分总结到此!

相关推荐
kyriewen几秒前
看了微软几万人用AI编程的数据——效率涨24%的代价没人提
前端·ai编程·claude
2601_963771372 分钟前
How to Scale Your WordPress Store Traffic in 2026
前端·php·plugin
亿元程序员11 分钟前
老板说我的3D箭头游戏用来做试玩太普通了,没人想玩,让我变点花样...
前端
李伟_Li慢慢1 小时前
01-threejs架构原理-课程简介
前端·three.js
_瑞2 小时前
深入理解 iOS 渲染原理
前端·ios
IT_陈寒2 小时前
SpringBoot自动配置失灵?你可能忘了这个关键注解
前端·人工智能·后端
iCOD3R3 小时前
Skill - kill-ai-slop 解决“AI 味”样式
前端·css·ai编程
shuaijie05183 小时前
强制修改调用接口的api地址。
javascript·vue.js·ecmascript
JerrySir3 小时前
恶意 npm 包只活了 17 分钟:技术面试里,为什么“升级依赖”还不算止血?
javascript·安全
皮音3 小时前
Skill 在项目中的实践 —— 从 Agent 困境到 Skill 工程化
前端