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

前端部分总结到此!

相关推荐
李剑一10 小时前
uni-app实现网络离线定位
前端·trae
鲨莎分不晴10 小时前
Nginx 部署前端项目实战指南
运维·前端·nginx
码界奇点10 小时前
基于Vue3与TypeScript的后台管理系统设计与实现
前端·javascript·typescript·vue·毕业设计·源代码管理
ashcn200110 小时前
水滴按钮解析
前端·javascript·css
攀登的牵牛花10 小时前
前端向架构突围系列 - 框架设计(五):契约继承原则
前端·架构
爱吃奶酪的松鼠丶11 小时前
React长列表,性能优化。关于循环遍历的时候,key是用对象数据中的ID还是用索引
javascript·react.js·性能优化
xkxnq11 小时前
第二阶段:Vue 组件化开发(第 17天)
javascript·vue.js·ecmascript
豆苗学前端11 小时前
你所不知道的前端知识,html篇(更新中)
前端·javascript·面试
一 乐11 小时前
绿色农产品销售|基于springboot + vue绿色农产品销售系统(源码+数据库+文档)
java·前端·数据库·vue.js·spring boot·后端·宠物
zzjyr11 小时前
Webpack 生命周期原理深度解析
前端