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

前端部分总结到此!

相关推荐
章豪Mrrey nical3 小时前
前后端分离工作详解Detailed Explanation of Frontend-Backend Separation Work
后端·前端框架·状态模式
hh随便起个名4 小时前
力扣二叉树的三种遍历
javascript·数据结构·算法·leetcode
我是小路路呀4 小时前
element级联选择器:已选中一个二级节点,随后又点击了一个一级节点(仅浏览,未确认选择),此时下拉框失去焦点并关闭
javascript·vue.js·elementui
程序员爱钓鱼5 小时前
Node.js 编程实战:文件读写操作
前端·后端·node.js
PineappleCoder5 小时前
工程化必备!SVG 雪碧图的最佳实践:ID 引用 + 缓存友好,无需手动算坐标
前端·性能优化
JIngJaneIL5 小时前
基于springboot + vue古城景区管理系统(源码+数据库+文档)
java·开发语言·前端·数据库·vue.js·spring boot·后端
敲敲了个代码5 小时前
隐式类型转换:哈基米 == 猫 ? true :false
开发语言·前端·javascript·学习·面试·web
澄江静如练_6 小时前
列表渲染(v-for)
前端·javascript·vue.js
JustHappy6 小时前
「chrome extensions🛠️」我写了一个超级简单的浏览器插件Vue开发模板
前端·javascript·github