react 基于canvas的图片验证码组件

该博客介绍了一个React组件——Captha,用于生成自定义的验证码。组件支持配置宽度、高度、颜色、字体大小、干扰线数量和点的数量。代码中包含了绘制文字、干扰线和点的方法,并提供了重新绘制验证码的功能。文章还提供了组件的完整代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

效果图

预览

使用

<Captha
        width={320}
        height={80}
        count={8}
        lineCount={20}
        pointCount={25}
        fontSize={40}
      />
      <Captha height={80} colors={['#000', '#333']} />
      <Captha
        datasets={'这是一个普通的验证码组件'.split('')}
        width={320}
        height={80}
        fontSize={22}
      />
      <Captha lineCount={0} height={80} pointCount={0} fontSize={12} />

代码

/* eslint-disable no-param-reassign */
import React, { useRef, useEffect, useState } from 'react';

// 默认的颜色
const COLORS = [
  '#2E57C9',
  '#04c56f',
  '#f39538',
  '#b757dc',
  '#e26d6d',
  '#8868ff',
  '#24cdd0',
  '#ffc84e',
  '#fe657f',
  '#748cfd',
];

// 角度转弧度
const getAngle = degree => (degree * Math.PI) / 180;

// 获取 [start-end] 范围内的随机数
const getRan = (start, end) =>
  Math.floor(Math.random() * (end - start) + start);

// 获取 colors 内的任意颜色
const getRanColor = colors => colors[getRan(0, colors.length)];

// 默认的随机数
const DATASETS = 'A,B,C,E,F,G,H,J,K,L,M,N,P,Q,R,S,T,W,X,Y,Z,1,2,3,4,5,6,7,8,9,0'.split(
  ',',
);

const draw = (
  ctx,
  strs,
  { width, height, colors, fontSize, lineCount, pointCount },
) => {
  // clear previous
  ctx.clearRect(0, 0, width, height);

  // drawText
  ctx.font = `bold ${fontSize}px Arial`;
  ctx.textBaseline = 'middle';

  const pl = width / (strs.length + 2);
  strs.forEach((c, i) => {
    const x = pl * (i + 1);
    const y = height / 2 + getRan(0, 6);
    const deg = getAngle(getRan(0, 30));
    const color = getRanColor(colors);

    ctx.fillStyle = color;
    ctx.translate(x, y);
    ctx.rotate(deg);
    ctx.fillText(c, 0, 0);
    ctx.rotate(-deg);
    ctx.translate(-x, -y);
  });
  // draw  points
  for (let i = 0; i < pointCount; i += 1) {
    const x = getRan(0, width);
    const y = getRan(0, height);

    ctx.strokeStyle = getRanColor(colors);
    ctx.beginPath();
    ctx.moveTo(x, y);
    ctx.lineTo(x + 1, y + 1);
    ctx.stroke();
  }
  // draw lines
  for (let i = 0; i < lineCount; i += 1) {
    ctx.strokeStyle = getRanColor(colors);
    ctx.beginPath();
    ctx.moveTo(getRan(0, width), getRan(0, height));
    ctx.lineTo(getRan(0, width), getRan(0, height));
    ctx.stroke();
  }
};

const getRanCaptha = (count, datasets) =>
  new Array(count).fill(null).map(() => datasets[getRan(0, datasets.length)]);

/**
 * @hook Captha
 * @desc 验证码组件
 * @ref https://developer.mozilla.org/zh-CN/docs/Web/API/CanvasRenderingContext2D
 * */
function Captha({
  style,
  width = 180, // 宽度
  height = 60, // 高度
  colors = COLORS, // 随机的颜色列表
  datasets = DATASETS, // 随机的验证码列表
  count = 4, // 个数
  fontSize = 32, // 字体大小
  lineCount = 5, // 干扰线个数
  pointCount = 20, // 干扰点个数
  onChange = captha => captha, // 验证码更新后的回调
}) {
  const [captha, setCaptha] = useState(getRanCaptha(count, datasets));
  const canvas = useRef(null);
  const context = useRef(null);

  useEffect(() => {
    context.current = canvas.current.getContext('2d');
  }, []);

  useEffect(() => {
    toDraw();

    if (onChange instanceof Function) {
      onChange(captha.join(''));
    }
  }, [captha]);

  const toDraw = () =>
    draw(context.current, captha, {
      width,
      height,
      colors,
      fontSize,
      lineCount,
      pointCount,
    });
  const reDraw = () => setCaptha(getRanCaptha(count, datasets));

  return (
    <canvas
      ref={canvas}
      width={width}
      height={height}
      style={style}   
      onClick={reDraw}
    />
  );
}
export default Captha;

more

https://github.com/Lemonreds/react-components/tree/master/src/components/Captha

可以使用第三方库 React Swipeable,它提供了一个 Swipeable 组件,可以使用触摸操作进行滑动。结合 Canvas 可以实现滑动验证码功能。 具体实现步骤如下: 1. 安装 React Swipeable:`npm install react-swipeable --save` 2. 创建 Swipeable 组件,并添加 onTouchEnd 事件监听: ```jsx import React from 'react'; import Swipeable from 'react-swipeable'; class SwipeableCanvas extends React.Component { handleSwipe = () => { // 滑动成功,执行相应操作 } render() { return ( <Swipeable onSwiped={this.handleSwipe}> <canvas width="300" height="150"></canvas> </Swipeable> ); } } export default SwipeableCanvas; ``` 3. 在 handleSwipe 方法中,获取 canvas 上下文并绘制验证码: ```jsx handleSwipe = () => { const canvas = document.getElementsByTagName('canvas')[0]; const ctx = canvas.getContext('2d'); const text = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678'; // 绘制背景 ctx.fillStyle = '#f5f5f5'; ctx.fillRect(0, 0, canvas.width, canvas.height); // 绘制文字 ctx.font = 'bold 50px Arial'; for (let i = 0; i < 4; i++) { const char = text.charAt(Math.floor(Math.random() * text.length)); ctx.fillStyle = `rgb(${Math.random() * 255},${Math.random() * 255},${Math.random() * 255})`; ctx.fillText(char, i * 70 + 20, 80); } } ``` 4. 在 Swipeable 组件中添加 onTouchMove 事件监听,实现滑动效果: ```jsx handleTouchMove = (e) => { e.preventDefault(); const canvas = document.getElementsByTagName('canvas')[0]; const ctx = canvas.getContext('2d'); // 获取 canvas 左边距离页面左边的距离 const canvasLeft = canvas.getBoundingClientRect().left; // 获取触摸点在 canvas 中的坐标 const touchX = e.changedTouches[0].clientX - canvasLeft; const touchY = e.changedTouches[0].clientY - canvas.offsetTop; // 绘制滑动轨迹 ctx.beginPath(); ctx.moveTo(this.lastX, this.lastY); ctx.lineTo(touchX, touchY); ctx.strokeStyle = '#000'; ctx.lineWidth = 5; ctx.stroke(); this.lastX = touchX; this.lastY = touchY; } handleSwipe = () => { // 判断滑动是否成功,执行相应操作 } handleTouchStart = (e) => { const canvas = document.getElementsByTagName('canvas')[0]; // 获取 canvas 左边距离页面左边的距离 const canvasLeft = canvas.getBoundingClientRect().left; // 获取触摸点在 canvas 中的坐标 this.lastX = e.changedTouches[0].clientX - canvasLeft; this.lastY = e.changedTouches[0].clientY - canvas.offsetTop; } render() { return ( <Swipeable onSwiped={this.handleSwipe} onSwiping={this.handleTouchMove} onSwipingStart={this.handleTouchStart} > <canvas width="300" height="150"></canvas> </Swipeable> ); } ``` 这样就可以实现一个基本的滑动验证码组件。需要注意的是,为了减少作弊行为,还需要在后端进行相应的验证。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值