react + zarm + react-captcha-code + classnames 实现登录注册页面

简介: react + zarm + react-captcha-code + classnames 实现登录注册页面

需要实现的效果

6a9f490060654a2a9d24ef94d68e63b6.png


代码实现过程

上一篇我们搭建了开发环境的基本结构:Vite 2.x + React + Zarm + Less + React Router v6 + Axios + flexible.js 搭建前端 H5 开发环境,下面我们开始实现登记注册页面的开发。


1.准备字体库

首先我们在https://www.iconfont.cn/新建一个项目


73092fd6fe434527be940d86850d3290.png


然后再项目里面添加字体图标,可以自己搜索想要的图标添加入库


e6e95853d5434d2b9167411f06e8e61f.png


然后把入库的图标添加到项目里

3eed2c8d3ebb47a2a6687db8610d7071.png


最后在我们项目那里生成在线链接即可


9b7fae2a8cb949e582d27aaa29a2aa9a.png



2.创建图标公用组件

我们新建 components/CustomIcon/index.jsx,添加如下代码:

// 自定义 Iconfont 图标,提供了一个 createFromIconfont 方法,方便开发者调用在 iconfont.cn 上自行管理的图标。
import { Icon } from 'zarm';
// 这里直接使用我们上面弄的项目字体链接
export default Icon.createFromIconfont('//at.alicdn.com/t/font_3376813_il53dc6ij5.js');


3.安装验证码插件

https://www.npmjs.com/package/react-captcha-code

基于 React 和 canvas 的一个验证码组件.

npm i react-captcha-code -S
import React, { useCallback, useRef } from 'react';
import Captcha from 'react-captcha-code';
export const Basic = () => {
  const handleChange = useCallback((captcha) => {
    console.log('captcha:', captcha);
  }, []);
  const captchaRef = useRef<HTMLCanvasElement>();
  const handleClick = () => {
    // 刷新验证码
    (captchaRef as any).current.refresh();
  };
  return (
    <>
      <Captcha ref={captchaRef} charNum={6} onChange={handleChange} />
      <div>
        <button onClick={handleClick}>更换验证码</button>
      </div>
    </>
  );
};



4.安装类名连接classnames

https://www.npmjs.com/package/classnames

一个简单的 JavaScript 实用程序,用于有条件地将类名连接在一起。

classNames('foo', 'bar'); // => 'foo bar'
classNames('foo', { bar: true }); // => 'foo bar'
classNames({ 'foo-bar': true }); // => 'foo-bar'
classNames({ 'foo-bar': false }); // => ''
classNames({ foo: true }, { bar: true }); // => 'foo bar'
classNames({ foo: true, bar: true }); // => 'foo bar'
// lots of arguments of various types
classNames('foo', { bar: true, duck: false }, 'baz', { quux: true }); // => 'foo bar baz quux'
// other falsy values are just ignored
classNames(null, false, 'bar', undefined, 0, 1, { baz: null }, ''); // => 'bar 1'


5.组件编写

我们新建 src/container/Login 文件夹,用于存放登录注册模块相关代码

116eb68d00f44be383cba52c4df23d50.png

交互逻辑:写在 index.jsx 里面

import { useState, useCallback } from 'react'
import { Cell, Input, Button, Toast } from 'zarm'
import CustomIcon from '@/components/CustomIcon'
import Captcha from "react-captcha-code"
import classNames from "classNames"
import { login, register } from "./api/index"
import s from './style.module.less'
const Login = () => {
  const [username, setUsername] = useState(''); // 账号
  const [password, setPassword] = useState(''); // 密码
  const [verify, setVerify] = useState(''); // 验证码
  const [captcha, setCaptcha] = useState(''); // 验证码变化后存储值
  const [type, setType] = useState('login'); // 登录注册类型
  // 验证码变化,回调方法
  const handleChange = useCallback((captcha) => {
    console.log('验证码变化,回调方法', captcha)
    setCaptcha(captcha)
  }, []);
  const onSubmit = async () => {
    if (!username) {
      Toast.show('请输入账号')
      return
    }
    if (!password) {
      Toast.show('请输入密码')
      return
    }
    try {
      // 判断是否是登录状态
      if (type == 'login') {
        // 执行登录接口,获取 token
        const { status, desc, data } = await login({
          username,
          password
        });
        console.log('登录接口', status, data)
        if(status === 200) {
          // 将 token 写入 localStorage
          localStorage.setItem('token', data.token);
          Toast.show('登录成功');
        } else {
          Toast.show(desc);
        }
      } else {
        if (!verify) {
          Toast.show('请输入验证码')
          return
        };
        if (verify != captcha) {
          Toast.show('验证码错误')
          return
        };
        const { status, desc, data } = await register({
          username,
          password
        });
        console.log('注册接口', status, data)
        if(status === 200) {
          Toast.show('注册成功');
          // 注册成功,自动将 tab 切换到 login 状态
          setType('login');
        } else {
          Toast.show(desc);
        }
      }
    } catch (error) {
      Toast.show('系统错误');
    }
  };
  return <div className={s.auth}>
    <div className={s.head} />
    <div className={s.tab}>
      <span className={classNames({ [s.avtive]: type == 'login' })} onClick={() => setType('login')}>登录</span>
      <span className={classNames({ [s.avtive]: type == 'register' })} onClick={() => setType('register')}>注册</span>
    </div>
    <div className={s.form}>
      <Cell icon={<CustomIcon type="user" />}>
        <Input
          clearable
          type="text"
          placeholder="请输入账号"
          onChange={(value) => setUsername(value)}
        />
      </Cell>
      <Cell icon={<CustomIcon type="password" />}>
        <Input
          clearable
          type="password"
          placeholder="请输入密码"
          onChange={(value) => setPassword(value)}
        />
      </Cell>
      {
        type == 'register' ? <Cell icon={<CustomIcon type="captcha" />}>
          <Input
            clearable
            type="text"
            placeholder="请输入验证码"
            onChange={(value) => setVerify(value)}
          />
          <Captcha charNum={4} onChange={handleChange} />
        </Cell> : null
      }
    </div>
    <div className={s.operation}>
      <Button block theme="primary" onClick={onSubmit}>{type == 'login' ? '登录' : '注册'}</Button>
    </div>
  </div>
}
export default Login



样式:写在 style.module.less 里,图片我这边放在了 src/assets/images 里面

.auth {
    min-height: 100vh;
    background-image: linear-gradient(217deg, #6fb9f8, #3daaf85e, #49d3fc1a, #3fd3ff00);
    .head {
      height: 200px;
        background: url('@/assets/images/cryptocurrency.png') no-repeat center;
        background-size: 120%;
        border-bottom-left-radius: 12px;
        border-bottom-right-radius: 12px;
        img {
          width: 34px;
          margin: 15px 0 0 15px;
        }
    }
    .tab {
      color: #597fe7;
      padding: 30px 24px 10px 24px;
      > span {
        margin-right: 10px;
        font-size: 14px;
        font-weight: bold;
        &.avtive {
          font-size: 20px;
          border-bottom: 2PX solid #597fe7;
          padding-bottom: 6px;
        }
      }
    }
    .form {
      padding: 0 6px;
      :global {
        .za-cell {
          background-color: transparent;
          &::after {
            border-top: none;
          }
        }
      }
    }
    .operation {
      padding: 10px 24px 0 24px;
    }
  }


接口配置:写在 api/index.js

import { fetchData } from "@/utils/axios.js";
// 注册
export function register(data) {
  return fetchData('/api/user/register', 'post', data);
}
// 登录
export function login(data) {
  return fetchData('/api/user/login', 'post', data);
}


6.测试

先注册已经注册过的账号试试:kaimo313,123456


b121c0ecd0dd4eff8856295b8b5eb588.png


注册正常的账号:注册成功之后就会切换到登录的模块


de4c141d81fb4dfaa2cbd96b2045356e.png



我们看到本地数据库里已经注册成功了。

1f85ffbb92a4406f88db4be9f9ea2a60.png


然后我们登录账号 kaimo313,123456

6908da3dfcf847679d498987bda98814.png


登录成功之后,token 会被存起来,然后跳转到我们的首页


a837ba5f2e314337b3d5b3d39b73dd9b.png












目录
相关文章
|
2月前
|
存储 前端开发 JavaScript
react怎么实现跨页面传参
react怎么实现跨页面传参
83 2
|
2月前
|
资源调度 JavaScript 前端开发
React-Router 5.0 制作导航栏+页面参数传递
React-Router 5.0 制作导航栏+页面参数传递
29 0
|
8月前
|
前端开发
react如何跳转页面?
react如何跳转页面?
|
2月前
|
数据采集 资源调度 前端开发
React的服务器端渲染:使用ReactDOMServer进行高效页面预渲染
【4月更文挑战第25天】使用ReactDOMServer,React支持服务器端渲染以实现高效预渲染。通过在Node.js环境中将React组件转化为HTML字符串,减少客户端JavaScript负载和渲染时间。优点包括更快首屏加载、改善SEO和兼容无JavaScript环境,但也会增加服务器负载、复杂性和状态管理挑战。开发者需根据项目需求平衡SSR和CSR。
|
2月前
|
前端开发
探索React页面导航:不只有React Router
探索React页面导航:不只有React Router
|
8月前
|
JavaScript 前端开发 虚拟化
理解React页面渲染原理,如何优化React性能?
理解React页面渲染原理,如何优化React性能?
73 0
|
2月前
|
JavaScript 前端开发
React 像 vue 一样配置页面路由,并支持重定向路由,路由守卫等(使用 useRoutes 完成)...
React 像 vue 一样配置页面路由,并支持重定向路由,路由守卫等(使用 useRoutes 完成)...
53 0
|
2月前
|
JavaScript 前端开发
React 像 vue 一样配置页面路由,并支持重定向路由,路由守卫等(使用 useRoutes 完成)
React 像 vue 一样配置页面路由,并支持重定向路由,路由守卫等(使用 useRoutes 完成)
36 0
|
7月前
|
前端开发
写一个react 的页面 录像组件
写一个react 的页面 录像组件
29 0
|
7月前
|
前端开发 CDN
在单html页面中使用react并配置jsx
在单html页面中使用react并配置jsx
35 0