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












目录
相关文章
|
存储 前端开发 JavaScript
react怎么实现跨页面传参
react怎么实现跨页面传参
382 2
|
资源调度 JavaScript 前端开发
React-Router 5.0 制作导航栏+页面参数传递
React-Router 5.0 制作导航栏+页面参数传递
148 0
|
前端开发 JavaScript
React项目路由懒加载lazy、Suspense,使第一次打开项目页面变快
本文介绍了在React项目中实现路由懒加载的方法,使用React提供的`lazy`和`Suspense`来优化项目首次加载的速度。通过将路由组件改为懒加载的方式,可以显著减少初始包的大小,从而加快首次加载速度。文章还展示了如何使用`Suspense`组件包裹`Switch`来实现懒加载过程中的fallback效果,并提供了使用前后的加载时间对比,说明了懒加载对性能的提升作用。
840 2
React项目路由懒加载lazy、Suspense,使第一次打开项目页面变快
|
2月前
|
编解码 前端开发 JavaScript
js react antd 实现页面低分变率和高分变率下字体大小自适用,主要是配置antd
在React中结合Ant Design与媒体查询,通过less变量和响应式断点动态调整`@font-size-base`,实现多分辨率下字体自适应,提升跨设备体验。
98 2
|
8月前
|
前端开发 JavaScript
除了使用Route组件,React Router还有其他方式处理404错误页面吗
除了使用Route组件,React Router还有其他方式处理404错误页面吗
226 58
|
8月前
|
前端开发
如何在React Router中定义404错误页面组件?
如何在React Router中定义404错误页面组件?
207 57
|
8月前
|
前端开发 UED
在React Router中,如何处理路由的404错误页面?
在React Router中,如何处理路由的404错误页面?
313 57
|
前端开发 JavaScript UED
react或者vue更改用户所属组,将页面所有数据进行替换(解决问题思路)____一个按钮使得页面所有接口重新请求
在React或Vue中,若需在更改用户所属组后更新页面所有数据但不刷新整个页面,可以通过改变路由出口的key值来实现。在用户切换组成功后,更新key值,这会触发React或Vue重新渲染路由出口下的所有组件,从而请求新的数据。这种方法避免了使用`window.location.reload()`导致的页面闪烁,提供了更流畅的用户体验。
160 1
react或者vue更改用户所属组,将页面所有数据进行替换(解决问题思路)____一个按钮使得页面所有接口重新请求
|
资源调度 前端开发 JavaScript
React中classnames库使用
【10月更文挑战第7天】
|
前端开发
React页面跳转取消上一个页面的所有请求
React页面跳转时取消上一个页面的所有axios请求,通过axios拦截器设置cancelToken,并在页面跳转时调用cancel函数取消未完成的请求。
306 2