antd快速开发(Form篇)

前言

由于一直在做中台业务,后台项目特别多,但是后台项目的特点是:大量的列表和大量表单,重复开发会降低效率,所以我这边总结了一下使用antd组件搭建form的快捷方法。希望能对大家有用。

传统Form搭建

首先传统搭建一个form表单,那么代码可能会是下面这样子

import React from 'react';
import { Form, Input } from 'antd'; @Form.create()
class MyTestForm extends React.Component {
render() {
const { form: { getFieldDecorator } } = this.props;
return(
<Form>
<Form.Item label='姓名'>
{
getFieldDecorator('username', {
rules: [
{
required: true,
message: '这是必填项'
}
]
})(<Input placeholder="placeholder" />)
}
</Form.Item>
<Form.Item label='密码'>
{
getFieldDecorator('password', {
rules: [
{
required: true,
message: '这是必填项'
}
]
})(<Input placeholder="placeholder" />)
}
</Form.Item>
</Form>
)
}
} export default MyTestForm;

目前只有两个表单项,看起来代码还挺清晰的,假如这个表单是很复杂的表单,有多个表单项,这块的代码会很长,维护和开发起来都是不方便,最重要的再来一个大的表单,你还是会需要写这么多的代码。这样就影响了开效率。

优化后的Form

我们想要的是,尽量少写(不写)重复性的代码,让代码的复用性更高。我这块做了一些优化,主要的流程如图:

主要的几个点:

  • 将最底层,最重要的部分抽离出来,也就是BaseItem组件,BaseItem具备的能力是form的能力,双向绑定的能力等,纯净的组件,不包含任何UI层面的东西。
  • UI层的东西也单独抽离出来,以方便以后UI层面的拓展。(例如想自己设计一套UI样式,就只用直接新开发一套UI层面的东西,而不用但心原子层组件的代码)。
  • 每个表单的信息抽离成配置文件,使页面维护起来更方便。

具体的代码如下

//BaseItem.js(原子层)
const BaseItem = (props) => {
const { form: { getFieldDecorator }, config } = props;
const { name, children, ...argv } = config;
return name ? getFieldDecorator(name, { ...argv })(children) : (children);
} export default BaseItem;
//ItemLayout.js(UI组件)
import React from 'react';
import { Form } from 'antd'; //Layout也可以用自己的UI组件
const Layout = ({ config: { itemOptions }, children }) =>
<Form.Item { ...itemOptions } >{ children }</Form.Item> const hidden = (isHidden) => {
const type = typeof(isHidden);
return (type === 'function' && isHidden()) || type === undefined || isHidden;
//默认是显示
} class ItemLayout extends React.Component {
render() {
const { children } = this.props;
return(
<>
{
React.Children.map(
children, (child, i) => {
const { config: { isHidden, ...argv}} = child.props;
return hidden(isHidden) ? null : //具有隐藏表单项能力
React.cloneElement(
<Layout { ...argv }>{ child }</Layout>,
{
...children.props
}
)
}
)
}
</>
)
}
} export default ItemLayout;
//config.js(配置文件)
import React from 'react';
import { Input } from 'antd'; export const formConfig = () => {
return [
{
itemOptions : { //Form.Item的api配置
label: '姓名'
//...argv
},
name: 'username',
initialValue: '',
rules: [],
children: <Input />
//...argv
},
{
itemOptions : {
label: '密码'
},
name: 'password',
initialValue: '',
rules: [],
children: <Input />,
isHidden: true //隐藏此项 默认是显示
},
{
itemOptions : {
label: '密码'
},
name: 'password',
initialValue: '',
rules: [],
children: <Input />,
isHidden: () => false //通过方法来动态显示隐藏
},
]
}

支持antd Form 所有的api

配置文件为什么是使用函数的形式?因为可以通过函数的参数,实现配置文件和页面之间进行数据的传递。

在页面就这样使用,代码如下

import React from 'react';
import { Form, Input } from 'antd';
import { formConfig } from './config.js';
import BaseItem from './BaseItem';
import ItemLayout from './ItemLayout'; @Form.create()
class MyTestForm extends React.Component {
render() {
const { form } = this.props;
return(
<Form>
{
formConfig().map((item, i) =>
<ItemLayout><BaseItem key={i} config={item} form={form}/></ItemLayout>)
}
</Form>
)
}
} export default MyTestForm;

相比传统搭建Form是不是快捷了很多,而且页面代码层面更显得更清晰。

注意:

假如是想使用自定义的组件,(一个个性化的业务组件),简单点,我对Input的封装

//自动trim的Input
import { Component } from 'react';
import { Input } from 'antd'; class TrimInput extends Component {
handleChange = (e) => {
e.target.value = e.target.value.trim();
this.props.onChange(e.target.value); //Input Chang 后将值传递给props
} render() {
const { value, ...argv } = this.props;
return(
<Input
value={ value } //将props的填在Input中
{ ...argv }
onChange={this.handleChange}/>
)
}
} export default TrimInput;

自定义的业务组件需要具备双向数据流的能力,最重要的一点是在更新的时候需要 调用this.props.onChange(data)

搜索Form包装(SearchForm

假如觉得这还不够过瘾,那么一起来基于BaseItem来再包装业务组件吧。相信每个后台都有搜索能力吧,那么我们就包装一个搜索的SearchForm

主要就是增加一个search功能并把form的值传递出去。

主要代码如下:

//searchForm.js
import React from 'react';
import { Form, Button } from 'antd'; import BaseItem from './BaseItem';
import ItemLayout from './ItemLayout'; @Form.create()
class SearchForm extends React.Component { handleSearch = () => {
const { form: { validateFields }, search } = this.props;
validateFields((err, fieldsValue) => {
console.log(fieldsValue);
if(!err) {
search && search(fieldsValue);
}
})
} render() {
const { form, searchConfig, search, form: { resetFields } } = this.props;
return(
<>
<Form onSubmit={this.handleSearch}>
{
searchConfig().map((item, i) =>
<ItemLayout><BaseItem key={i} config={item} form={form}/></ItemLayout>)
}
{
search && <div>
<Button htmlType="submit" type="primary" style={{marginRight: '20px'}}>
搜索
</Button>
<Button onClick={() => resetFields()}>重置</Button>
</div>
}
</Form>
</>
)
}
} export default SearchForm;

页面里面使用,表单项还是抽成配置文件使用:

//config.js 查询条件
export const searchConfig = () => {
return [
{
itemOptions : {
label: '条件一'
},
name: 'name1',
initialValue: '',
rules: [],
children: <Input />
},
{
itemOptions : {
label: '条件二'
},
name: 'name2',
initialValue: '',
rules: [],
children: <Input />
}
]
}
import React from 'react';
import { searchConfig } from './config';
import SearchForm from './SearchForm'; class MyTestForm extends React.Component {
handleSearch = value => {
console.log(value);//获取到的查询条件
}
render() {
return(
<SearchForm searchConfig={searchConfig} search={this.handleSearch} />
)
}
} export default MyTestForm;

这样子写查询表单是不是很快呀,以后遇到查询就引用这个组件,然后抽一个配置文件,这样就OK了。

Modal + Form

还有也会经常遇到这种情况,弹窗里面的Form,这样子就需要给弹窗增加收集数据的能力。相当于我们把searchForm的组件放在 Modal 里面。 具体实现代码就不贴了。

antd Form 需要注意的几个问题。

  1. initialValue 这个属性只是设置表单的初始值,当需要动态更改表单的值的时候,使用 setFieldsValue

  2. resetFields这个属性是重置一组输入控件的值与状态,(将值重置为initialValue , 而不是清空数据,需要清空数据还是使用setFieldsValue

antd Form 新的改动

antd Form 将在第4个版本使用 rc-field-form, 但是还没有发布,我是在4.0-prepare分支上看到。

那么两个底层组件 有什么区别呢?

首先rc-field-form 会尽量在api层面上保持一致,但是仍有地方做了改动。 主要是以下几点:

  • 当没有手动更新过表单的时候,将不会收集initialValues 的值

    rc-form里面,如果用户没有操作过表单,将会从form的initialValues 收集值。他们认为这是一个bug,但是好多用户是用了这个,所以他们不做修复。在rc-field-form中,将不会有这个bug。如果想改变组件的值,使用 setFieldsValue 代替。

  • 嵌套的name使用数组代替字符串

    rc-form里面支持user.name,最终会被解释成为{user:{ name: '' } }

    rc-field-form将是['user', 'name'] 解释成为 {user: { name: '' }} 并且会把 user.name解释成为{ ['user.name']: ''}

  • 删除validateFieldsAndScroll这个属性

    是因为使用了findDomNode,但是findDomNodeStrictMode中被标记为警告。认为这是对表单组件的过度控制。

  • getFieldsError 将总是返回来数组

    rc-form 当没有错的时候,返回的是null,rc-field-form现在返回的是一个空数组

  • 删除了validateFields的callback函数

    是因为ES8支持async/await,没有理由不使用它。我们使用的时候应该是

    async function() {
    try {
    const values = await form.validateFields();
    console.log(values);
    } catch (errorList) {
    errorList.forEach(({ name, errors }) => {
    // Do something...
    });
    }
    }
  • setFields将不触发onFieldsChangesetFieldsValue不触发onValuesChange

    总结

写这篇文章主要是自己做后台最Form的总结,还有是为大家提供一种思路,后台快速开发的方式。

后面还会更新其它antd 组件,主要是如何开发更适合业务场景的组件。

antd快速开发(Form篇)的更多相关文章

  1. 使用 dva + antd 快速开发react应用

    使用 dva + antd 快速开发react应用 版本说明: 注意:dva的版本是0.9.2 $ node -v v10.2.1 $ npm -v $ dva -v dva-cli version ...

  2. 【技术博客】基于vue的前端快速开发(工具篇)

    一.Vue教程 vue.js是一套构建用户界面的渐进式框架.vue采用自底向上增量开发的设计.vue的核心库只关心视图层,非常容易学习,非常容易与其它库和已有项目整合.vue完全有能力驱动采用单文件组 ...

  3. vue+uni-app商城实战 | 第一篇:【有来小店】微信小程序快速开发接入Spring Cloud OAuth2认证中心完成授权登录

    一. 前言 本篇通过实战来讲述如何使用uni-app快速进行商城微信小程序的开发以及小程序如何接入后台Spring Cloud微服务. 有来商城 youlai-mall 项目是一套全栈商城系统,技术栈 ...

  4. Android开源项目发现--- 工具类快速开发篇(持续更新)

    1. Guava Google的基于java1.6的类库集合的扩展项目 包括collections, caching, primitives support, concurrency librarie ...

  5. vivo浏览器的快速开发平台实践-总览篇

    一.什么是快速开发平台 快速开发平台,顾名思义就是可以使得开发更为快速的开发平台,是提高团队开发效率的生产力工具.近一两年,国内很多公司越来越注重研发效能的度量和提升,基于软件开发的特点,覆盖管理和优 ...

  6. 微信小程序快速开发上手

    微信小程序快速开发上手 介绍: 从实战开发角度,完整系统地介绍了小程序的开发环境.小程序的结构.小程序的组件与小程序的API,并提供了多个开发实例帮助读者快速掌握小程序的开发技能,并能自己动手开发出小 ...

  7. Django+easyui 快速开发

    Django的使用我们可以查看上一篇博客,今天我们要在Django中使用easyui快速开发,在我们安装好Django, 我们可以道改地址那一下easyui 官方API文档(http://downlo ...

  8. JeecgBoot 2.1.1 代码生成器AI版本发布,基于SpringBoot+AntDesign的JAVA快速开发平台

    此版本重点升级了 Online 代码生成器,支持更多的控件生成,所见即所得,极大的提高开发效率:同时做了数据库兼容专项工作,让 Online 开发兼容更多数据库:Mysql.SqlServer.Ora ...

  9. 实用 | 利用 aardio 配合 Python 快速开发桌面应用

    1. 前言 大家好,我是安果! 我们都知道 Python 可以用来开发桌面应用,一旦功能开发完成,最后打包的可执行文件体积大,并且使用 Python 开发桌面应用周期相对较长 假如想快速开发一款 PC ...

随机推荐

  1. Linux性能优化实战学习笔记:第三十五讲

    一.上节回顾 前面内容,我们学习了 Linux 网络的基础原理以及性能观测方法.简单回顾一下,Linux网络基于 TCP/IP 模型,构建了其网络协议栈,把繁杂的网络功能划分为应用层.传输层.网络层. ...

  2. [LeetCode] 14. Longest Common Prefix 最长共同前缀

    Write a function to find the longest common prefix string amongst an array of strings. If there is n ...

  3. 热情组——项目冲刺 Day4

    项目相关 作业相关 具体描述 班级 班级链接 作业要求 链接地址 团队名称 热情组 作业目标 实现软件制作,以及在福大的传播 Github链接 链接地址 SCRUM部分: 成员昵称 昨日目标 开始时间 ...

  4. MySQL基础指令和安装

    数据库概念 那Mysql能干嘛呢?它就是一款软件,安装在任何一台计算机或者服务器上的时候,只要我告诉它创建一个文件,新增一个数据,删除一个数据它就能帮我去做想要的操作 那我们暂且能不能理解为mysql ...

  5. .NET Core:Json和XML

    (1)Json WebAPI默认使用Json格式,如果需要更改默认的Json设置在Startup的ConfigureServices方法中修改:services.AddMvc() .AddJsonOp ...

  6. dataframe 基本操作

    package com.jason.example import org.apache.spark.sql.functions.broadcast class DFTest extends Spark ...

  7. centos 安装 oracle11r2

    因为要测试spark链接oracle,所以需要再服务器装oracle 1.下载oracle, 如果自己下载需要注册,比较麻烦,可以直接用如下命令下载 因为zip比较大,建议nohup 后台下载 noh ...

  8. Ajax 跨域请求,Chrome 无法显示 Set-Cookie

    在使用 Ajax 进行跨域请求时,前后端均已设置 withCredentials = true,但 Chrome 前端响应无法显示 Set-Cookie. 一开始以为 Cookie 并没有设置成功,但 ...

  9. [转帖]PG的时间函数使用整理如下

    PG的时间函数使用整理如下 https://blog.csdn.net/dahuzix/article/details/48576945 1.获取系统时间函数 -- :: -- :: -- :: 2. ...

  10. 在Button样式中添加EventSetter,理解路由事件

    XML <Window.Resources> <Style x:Key="ButtonStyle2" TargetType="{x:Type Butto ...