詳解對於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登錄內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀:

    None Found