详解对于React结合Antd的Form组件实现登录功能

一、React 结合 Antd 实现登录功能

引入所需的 Antd 组件,代码如下所示:

import { Form, Icon, Input, Button, message } from 'antd'

在 Login.jsx 中,创建一个 Login 组件。当对外暴露组件时,需要使用 Form 组件进行包装,包装 Form 组件生成一个新的组件 Form(Login),同时新组件会向 Form 组件传递一个强大的对象属性 form,这样就可以取到 Form 表单的值,这也是高阶组件和高阶函数的体现,代码如下所示:

class Login extends Component {}
const WrapLogin = Form.create()(Login)
export default WrapLogin

在 render 内部去渲染表单时,可以先通过 this.props 去拿到 form 表单,在 form 中取得 getFieldDecorator,用于和表单进行双向绑定。在 getFieldDecorator 中,第一项是表单项对应的 value 值,第二项是配置对象,属性名是特定的一些名称。比如,rules 是验证规则,在 rules 中,可以设置 required 为是否必选,message 为校验文案,pattern 为正则表达式校验,max 为最大长度,min 为最小长度。还比如 initialValue 是表单项的初始值。对于 rules 校验,可以使用声明式验证, 也就是直接使用别人定义好的验证规则进行验证,还可以自定义验证 validator,function(rule, value, callback),必须有 callback 回调函数,代码如下所示:

class Login extends Component {
 validPwd = (rule, value, callback) => {
  if (!value) {
   callback('密码必须输入')
  } else if (value.length < 4) {
   callback('密码长度不能小于4位')
  } else if (value.length > 12) {
   callback('密码长度不能大于12位')
  } else if (!/^[a-zA-Z0-9_]+$/.test(value)) {
   callback('密码必须是英文、数字或下划线组成')
  } else {
   callback()
  }
 }

 render () {
  const form = this.props.form
  const { getFieldDecorator } = form

  return (
   <div className="login">
    <header className="login-header">
     <img src={logo} alt="logo"></img>
     <h1>React 后台管理系统</h1>
    </header>
    <section className="login-content">
     <h2>用户登录</h2>
     <Form>
      <Form.Item>
       {
        getFieldDecorator('username', {
         rules: [
          { required: true, whitespace: true, message: '用户名必须输入'},
          { min: 4, message: '用户名至少是4位'},
          { max: 12, message: '用户名至少是12位'},
          { pattern: /^[a-zA-Z0-9_]+$/, message: '用户名必须是英文、数字或下划线组成'}
         ],
         // initialValue: 'admin',
        })(
         <Input
          prefix={<Icon type="user" style={{ color: 'rgba(0,0,0,.25)' }} />}
          placeholder="用户名"
         />
        )
       }
      </Form.Item>
      <Form.Item>
       {
        getFieldDecorator('password', {
         rules: [
          { validator: this.validPwd }
         ]
        })(
         <Input
          prefix={<Icon type="lock" style={{ color: 'rgba(0,0,0,.25)' }} />}
          type="password"
          placeholder="密码"
         />
        )
       }
      </Form.Item>
      <Form.Item>
       <Button type="primary" htmlType="submit" className="login-form-button">
         登陆
       </Button>
      </Form.Item>
     </Form>
    </section>
   </div>
  )
 }
}

const WrapLogin = Form.create()(Login)
export default WrapLogin

我们可以定义两个工具类,用来操作登录对象,memoryUtils 是用来在内存保存一些数据的工具模块,storageUtils 是进行 local 数据存储管理的工具模块,如下所示:

memoryUtils.js,代码如下所示:

export default {
 user: {},
 product: {}
}

storageUtils.js,代码如下所示:

import store from 'store'

const USER_KEY = 'user_key'

export default {
 // 保存 user
 saveUser (user) {
  store.set(USER_KEY, user)
 },

 // 读取 user
 getUser () {
  return store.get(USER_KEY) || {}
 },

 // 删除 user
 removeUser () {
  store.remove(USER_KEY)
 }
}

定义登录的接口请求函数,使用 axios 可以先进行封装,得到 response.data,如下所示:

ajax.js,代码如下所示:

import axios from 'axios'
import {message} from 'antd'

export default function ajax(url, data={}, type='GET') {

 return new Promise((resolve, reject) => {
  let promise
  if(type==='GET') {
   promise = axios.get(url, {
    params: data
   })
  } else {
   promise = axios.post(url, data)
  }
  promise.then(response => {
   resolve(response.data)
  }).catch(error => {
   message.error('请求出错了: ' + error.message)
  })
 })

}

index.js,代码如下所示:

import jsonp from 'jsonp'
import ajax from './ajax'
import { message } from 'antd'

const BASE = ''

export const reqLogin = (username, password) => ajax(BASE + '/login', { username, password}, 'POST')

export const reqCategories = (parentId) => ajax(BASE + '/manage/category/list', {parentId})

export const reqAddCategories = ({parentId, categoryName}) => ajax(BASE + '/manage/category/add', {parentId, categoryName}, 'POST')

export const reqUpdateCategories = ({categoryId, categoryName}) => ajax(BASE + '/manage/category/update', {categoryId, categoryName}, 'POST')

export const reqCategory = (categoryId) => ajax(BASE + '/manage/category/info', { categoryId })

export const reqProducts = ({pageNum, pageSize}) => ajax(BASE + '/manage/product/list', { pageNum, pageSize})

export const reqUpdateStatus = ({productId, status}) => ajax(BASE + '/manage/product/updateStatus', {productId, status}, 'POST')

export const reqSearchProducts = ({ pageNum, pageSize, searchName, searchType}) => ajax(BASE + '/manage/product/search', {
 pageNum,
 pageSize,
 [searchType]: searchName
})

export const reqDeleteImg = (name) => ajax(BASE + '/manage/img/delete', {name}, 'POST')

export const reqAddUpdateProduct = (product) => ajax(BASE + '/manage/product/' + (product._id ? 'update' : 'add'), product, 'POST')

export const reqRoles = () => ajax(BASE + '/manage/role/list')

export const reqAddRole = (roleName) => ajax(BASE + '/manage/role/add', {roleName}, 'POST')

export const reqUpdateRole = (role) => ajax(BASE + '/manage/role/update', role, 'POST')

export const reqUsers = () => ajax(BASE + '/manage/user/list')

export const reqDeleteUser = (userId) => ajax(BASE + '/manage/user/delete', {userId}, 'POST')

export const reqAddOrUpdateUser = (user) => ajax(BASE + '/manage/user/'+(user._id ? 'update': 'add'), user, 'POST')

export const reqWeather = (city) => {

 return new Promise((resolve, reject) => {
  const url = `http://api.map.baidu.com/telematics/v3/weather?location=${city}&output=json&ak=IOXimfoqOUVq2KcYCiQU9cMF7hyN5kFB`
  jsonp(url, {}, (err, data) => {
   console.log('jsonp()', err, data)
   if (!err && data.status==='success') {
    const {dayPictureUrl, weather} = data.results[0].weather_data[0]
    resolve({dayPictureUrl, weather})
   } else {
    message.error('获取天气信息失败!')
   }

  })
 })
}

引入这些工具类和接口,代码如下所示:

import { reqLogin } from '../../api'
import memoryUtils from '../../utils/memoryUtils'
import storageUtils from '../../utils/storageUtils'

给 Form 表单绑定 onSubmit 事件,handleSubmit。在这个事件中,需要先使用 event.preventDefault() 阻止事件的默认行为。如果想要获取表单项的输入数据,可以使用 form.getFieldsValue()。但是,在提交表单前需要对表单数据进行预校验,使用 this.props.form.validateFields 进行预校验,validateFields 可以获取所有表单字段的值,并且可以判断表单数据是否有错。如有 没错,说明预校验通过,从 values 中获取 username 和 password 的值,然后通过 reqLogin 这个接口结合 async 和 await 发起登录请求。如果响应的状态码正确,说明登录成功,保存 user,保存在内存和本地中,然后使用 this.props.history.replace 跳转到主管理界面中,反之则登录失败。在 render 中,如果用户已经登陆, 需要使用 Redirect 自动跳转到主管理界面中,代码如下所示:

 handleSubmit = (event) => {
  event.preventDefault()

  this.props.form.validateFields(async (err, values) => {
   if (!err) {
    const { username, password } = values
    const result = await reqLogin(username, password)
    if (result.status === 0) {
     message.success('登录成功')
     const user = result.data
     memoryUtils.user = user
     storageUtils.saveUser(user)
     this.props.history.replace('/')
    } else {
     message.error(result.msg)
    }
   } else {
    console.log(err)
   }
  })

二、React 结合 Antd 实现登录功能的实现

React 结合 Antd 实现登录功能的实现,完整代码如下所示:
login.jsx,代码如下所示:

import React, { Component } from 'react'
import { Form, Icon, Input, Button, message } from 'antd'
import { Redirect } from 'react-router-dom'
import './login.less'
import logo from '../../assets/images/logo.png'
import { reqLogin } from '../../api'
import memoryUtils from '../../utils/memoryUtils'
import storageUtils from '../../utils/storageUtils'

class Login extends Component {

 handleSubmit = (event) => {
  event.preventDefault()

  this.props.form.validateFields(async (err, values) => {
   if (!err) {
    const { username, password } = values
    const result = await reqLogin(username, password)
    if (result.status === 0) {
     message.success('登录成功')
     const user = result.data
     memoryUtils.user = user
     storageUtils.saveUser(user)

     this.props.history.replace('/')
    } else {
     message.error(result.msg)
    }
   } else {
    console.log(err)
   }
  })

 }

 validPwd = (rule, value, callback) => {
  if (!value) {
   callback('密码必须输入')
  } else if (value.length < 4) {
   callback('密码长度不能小于4位')
  } else if (value.length > 12) {
   callback('密码长度不能大于12位')
  } else if (!/^[a-zA-Z0-9_]+$/.test(value)) {
   callback('密码必须是英文、数字或下划线组成')
  } else {
   callback()
  }
 }

 render () {

  const user = memoryUtils.user
  if (user && user._id) {
   return <Redirect to="/"></Redirect>
  }

  const form = this.props.form
  const { getFieldDecorator } = form

  return (
   <div className="login">
    <header className="login-header">
     <img src={logo} alt="logo"></img>
     <h1>React 后台管理系统</h1>
    </header>
    <section className="login-content">
     <h2>用户登录</h2>
     <Form onSubmit={this.handleSubmit}>
      <Form.Item>
       {
        getFieldDecorator('username', {
         rules: [
          { required: true, whitespace: true, message: '用户名必须输入'},
          { min: 4, message: '用户名至少是4位'},
          { max: 12, message: '用户名至少是12位'},
          { pattern: /^[a-zA-Z0-9_]+$/, message: '用户名必须是英文、数字或下划线组成'}
         ],
         // initialValue: 'admin',
        })(
         <Input
          prefix={<Icon type="user" style={{ color: 'rgba(0,0,0,.25)' }} />}
          placeholder="用户名"
         />
        )
       }
      </Form.Item>
      <Form.Item>
       {
        getFieldDecorator('password', {
         rules: [
          { validator: this.validPwd }
         ]
        })(
         <Input
          prefix={<Icon type="lock" style={{ color: 'rgba(0,0,0,.25)' }} />}
          type="password"
          placeholder="密码"
         />
        )
       }
      </Form.Item>
      <Form.Item>
       <Button type="primary" htmlType="submit" className="login-form-button">
         登陆
       </Button>
      </Form.Item>
     </Form>
    </section>
   </div>
  )
 }
}

const WrapLogin = Form.create()(Login)
export default WrapLogin

login.less,代码如下所示:

.login {
 width: 100%;
 height: 100%;
 background-image: url('./images/bg.jpg');
 background-size: 100% 100%;
 .login-header {
  display: flex;
  align-items: center;
  height: 80px;
  background-color: rgba(21, 20, 13, 0.5);
  img {
   width: 40px;
   height: 40px;
   margin: 0 15px 0 50px;
  }
  h1 {
   font-size: 30px;
   color: white;
  }
 }

 .login-content {
  width: 400px;
  height: 300px;
  background-color: #fff;
  margin: 50px auto;
  padding: 20px 40px;
  h2 {
   text-align: center;
   font-size: 30px;
   font-weight:bold;
   margin-bottom: 20px;
  }
  .login-form {
   .login-form-button {
    width: 100%;
   }
  }
 }
}

到此这篇关于详解对于React结合Antd的Form组件实现登录功能的文章就介绍到这了,更多相关React Antd Form登录内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • React Form组件的实现封装杂谈

    前言 对于网页系统来说,表单提交是一种很常见的与用户交互的方式,比如提交订单的时候,需要输入收件人.手机号.地址等信息,又或者对系统进行设置的时候,需要填写一些个人偏好的信息. 表单提交是一种结构化的操作,可以通过封装一些通用的功能达到简化开发的目的.本文将讨论Form表单组件设计的思路,并结合有赞的ZentForm组件介绍具体的实现方式.本文所涉及的代码都是基于React v15的版本. Form组件功能 一般来说,Form组件的功能包括以下几点: 表单布局 表单字段 封装表单验证&错误提示

  • React如何利用Antd的Form组件实现表单功能详解

    一.构造组件 1.表单一定会包含表单域,表单域可以是输入控件,标准表单域,标签,下拉菜单,文本域等. 这里先引用了封装的表单域 <Form.Item /> 2.使用Form.create处理后的表单具有自动收集数据并校验的功能,但如果不需要这个功能,或者默认的行为无法满足业务需求,可以选择不使用Form.create并自行处理数据 经过Form.create()包装过的组件会自带this.props.form属性,this.props.form提供了很多API来处理数据,如getFieldDe

  • 在react项目中使用antd的form组件,动态设置input框的值

    问题: 创建账号时,输入账号后不搜索直接保存,提示查询后,再点搜索就不能搜索这个账号了 原因: 点击保存之后,对表单进行了验证,导致之后请求的数据无法在更新到input框中,也就是说即使在state中有值,也不会更新initialValue值,就导致搜索后的值不能正确填入input中,表单也就提交不了. 解决办法: 不使用initialValue设置动态更新的值,而是使用 this.props.form.setFieldValue({name:data}); 用于动态更新值,就可以解决了. if

  • 详解对于React结合Antd的Form组件实现登录功能

    一.React 结合 Antd 实现登录功能 引入所需的 Antd 组件,代码如下所示: import { Form, Icon, Input, Button, message } from 'antd' 在 Login.jsx 中,创建一个 Login 组件.当对外暴露组件时,需要使用 Form 组件进行包装,包装 Form 组件生成一个新的组件 Form(Login),同时新组件会向 Form 组件传递一个强大的对象属性 form,这样就可以取到 Form 表单的值,这也是高阶组件和高阶函数

  • 详解 Spring注解的(List&Map)特殊注入功能

    详解 Spring注解的(List&Map)特殊注入功能 最近接手一个新项目,已经没有原开发人员维护了.项目框架是基于spring boot进行开发.其中有两处Spring的注解花费了大量的时间才弄明白到底是怎么用的,这也涉及到spring注解的一个特殊的注入功能. 首先,看到代码中有直接注入一个List和一个Map的.示例代码如下: @Autowired private List<DemoService> demoServices; @Autowired private Map<

  • react实现antd线上主题动态切换功能

    demo 框架选择: create-react-app + mobx + webpack5 + antdesign 说明 由于最近公司有多个主题的共存性,所以需要实现线上主题切换的功能,所以本文主要描述的是基于create-react-app之上的主题切换. CSS切换 有考虑过根据用户选择的主题在切换的时候选择加载页面css文件的区分方案,但是考虑到这种形式需要在页面切换的时候去reload,因为htmlDOM是在css与JS的结合产物,用户体验不是很好. Less切换 单纯引入所有的less

  • 解决antd的Form组件setFieldsValue的警告问题

    记住:setFieldsValue的字段要对应得上 解决antd的Form组件setFieldsValue的警告 使用antd的Form组件setFieldsValue可能会出现You cannot set a form field before rendering a field associated with the value.警告,字面意义去看是说在 render之前设置了表单值的问题. 解决 在使用setFieldsValue给表单Form的某一个filed赋值时,可能掺杂了非表单控件

  • 详解IDEA中SpringBoot整合Servlet三大组件的过程

    Spring MVC整合 SpringBoot提供为整合MVC框架提供的功能特性 内置两个视图解析器:ContentNegotiatingViewResolver和BeanNameViewResolver 支持静态资源以及WebJars 自动注册了转换器和格式化器 支持Http消息转换器 自动注册了消息代码解析器 支持静态项目首页index.html 支持定制应用图标favicon.ico 自动初始化Web数据绑定器:ConfigurableWebBindingInitializer Sprin

  • 详解Vue.js 可拖放文本框组件的使用

    可拖放文本框允许用户通过拖动备选项至文本框来确定输入,其实也可以说是 combobox 的一种变形. 与 combobox 相比,这种组件能让用户更加直观的看到所有备选项,并且可以是多个输入共用一组备选项. 类似的组件也曾用在 3D Windrose App,Graph Maker App 等多个 app 里. 注册组件 注册可拖放文本框组件(其实就是将封装好的这部分代码 Ctrl+C and Ctrl+V). <script type="text/x-template" id=

  • 详解基于Vue cli开发修改外部组件Vant默认样式

    前言 在引入外部组件的时候,想要修改默认样式,可以通过class修改,但一般会有权重不够等各种原因,官网其实列出了一套主题定制的方案,通过覆盖配置文件来修改样式,官网地址:主题定制 提示:以下是本篇文章正文内容,下面案例可供参考 一.Less 因为Vant 使用了 Less 对样式进行预处理,并内置了一些样式变量,可以通过替换样式变量即可定制你自己需要的主题. 给你的项目配置less: npm install less --save-dev npm install less-loader --s

  • 详解使用React进行组件库开发

    最近针对日常业务需求使用react封装了一套[组件库], 大概记录下整个开发过程中的心得.由于篇幅原因,在这里只对开发过程中比较纠结的选型和打包等进行讨论,后续再对具体组件的封装进行讨论. 概述 我们都知道,组件化的开发模式对于我们的开发效率有着极大的提升,针对我们日常使用的基本组件进行封装,可以大量的简化我们对于基本UI的关注度,让我们的工作聚焦在业务逻辑上,很好的分离业务与基础UI的代码,使得整个项目更有调理,这也是我们要进行本组件库开发的原因. 然而现有React开源组件有很多,像ant-

随机推荐