antd快速开发(Form篇)
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  需要注意的几个问题。
- initialValue这个属性只是设置表单的初始值,当需要动态更改表单的值的时候,使用- setFieldsValue
- 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,但是- findDomNode在- StrictMode中被标记为警告。认为这是对表单组件的过度控制。
- 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将不触发- onFieldsChange和- setFieldsValue不触发- onValuesChange- 总结
写这篇文章主要是自己做后台最Form的总结,还有是为大家提供一种思路,后台快速开发的方式。
后面还会更新其它antd 组件,主要是如何开发更适合业务场景的组件。

antd快速开发(Form篇)的更多相关文章
- 使用 dva + antd 快速开发react应用
		使用 dva + antd 快速开发react应用 版本说明: 注意:dva的版本是0.9.2 $ node -v v10.2.1 $ npm -v $ dva -v dva-cli version ... 
- 【技术博客】基于vue的前端快速开发(工具篇)
		一.Vue教程 vue.js是一套构建用户界面的渐进式框架.vue采用自底向上增量开发的设计.vue的核心库只关心视图层,非常容易学习,非常容易与其它库和已有项目整合.vue完全有能力驱动采用单文件组 ... 
- vue+uni-app商城实战 | 第一篇:【有来小店】微信小程序快速开发接入Spring Cloud OAuth2认证中心完成授权登录
		一. 前言 本篇通过实战来讲述如何使用uni-app快速进行商城微信小程序的开发以及小程序如何接入后台Spring Cloud微服务. 有来商城 youlai-mall 项目是一套全栈商城系统,技术栈 ... 
- Android开源项目发现--- 工具类快速开发篇(持续更新)
		1. Guava Google的基于java1.6的类库集合的扩展项目 包括collections, caching, primitives support, concurrency librarie ... 
- vivo浏览器的快速开发平台实践-总览篇
		一.什么是快速开发平台 快速开发平台,顾名思义就是可以使得开发更为快速的开发平台,是提高团队开发效率的生产力工具.近一两年,国内很多公司越来越注重研发效能的度量和提升,基于软件开发的特点,覆盖管理和优 ... 
- 微信小程序快速开发上手
		微信小程序快速开发上手 介绍: 从实战开发角度,完整系统地介绍了小程序的开发环境.小程序的结构.小程序的组件与小程序的API,并提供了多个开发实例帮助读者快速掌握小程序的开发技能,并能自己动手开发出小 ... 
- Django+easyui 快速开发
		Django的使用我们可以查看上一篇博客,今天我们要在Django中使用easyui快速开发,在我们安装好Django, 我们可以道改地址那一下easyui 官方API文档(http://downlo ... 
- JeecgBoot 2.1.1 代码生成器AI版本发布,基于SpringBoot+AntDesign的JAVA快速开发平台
		此版本重点升级了 Online 代码生成器,支持更多的控件生成,所见即所得,极大的提高开发效率:同时做了数据库兼容专项工作,让 Online 开发兼容更多数据库:Mysql.SqlServer.Ora ... 
- 实用 | 利用 aardio 配合 Python 快速开发桌面应用
		1. 前言 大家好,我是安果! 我们都知道 Python 可以用来开发桌面应用,一旦功能开发完成,最后打包的可执行文件体积大,并且使用 Python 开发桌面应用周期相对较长 假如想快速开发一款 PC ... 
随机推荐
- 【LGR-060】洛谷10月月赛 I
			A - 打字练习 出题:memset0 送分模拟题,按题意模拟即可. 需要注意的是对退格键的判断,如果光标已经在行首,则直接忽略被读入的退格键. B - 小猪佩奇爬树 出题:_QAQ 维护所有相同节点 ... 
- [转载]3.2 UiPath鼠标操作文本的介绍和使用
			一.鼠标(mouse)操作的介绍 模拟用户使用鼠标操作的一种行为,例如单击,双击,悬浮.根据作用对象的不同我们可以分为对元素的操作.对文本的操作和对图像的操作 二.鼠标对文本的操作在UiPath中的使 ... 
- Docker 镜像/容器操作命令
			一.镜像操作 1.拉取镜像 # docker pull tomcat # docker pull tomcat:8.0.21-jre8 # docker pull 192.168.220.150: ... 
- MyBatis 通过 BATCH 批量提交
			本文由 简悦 SimpRead 转码, 原文地址 https://www.jb51.net/article/153382.htm 很多人在用 MyBatis 或者 通用 Mapper 时,经常会问有没 ... 
- Flink DataStream 编程入门
			流处理是 Flink 的核心,流处理的数据集用 DataStream 表示.数据流从可以从各种各样的数据源中创建(消息队列.Socket 和 文件等),经过 DataStream 的各种 transf ... 
- jQuery实现C#CheckBoxList模糊搜索
			前言 最近开发的一套系统中需要对商品进行管理,在选择商品时,要分别从品牌.型号.商品三个类别分别选择对应的选项才能找到需要的商品,三者的关系为:品牌包含型号,型号包含商品,因此使用了三个不同的 asp ... 
- 小程序上传图片功能 uploadFile:fail Read error:ssl=0xa738d808:I/O error during system call,Connection reset by peer
			由于纯网页上传图片小程序会闪退,就采用了小程序原生的上传功能wx.uploadfile 处理流程: 1.网页需要跳转到小程序 需要引用 <script src='https://res.wx.q ... 
- 获取PostgreSQL数据库中得JSON值
			在PostgreSQL数据库中有一列为JSON,要获取JSON中得数据可以用下面sql: select orderno as OrderNo ,amount as Amount ,ordertime ... 
- BAT: Windows批处理更改当前工作路径
			最近项目上需要获取文件夹下所有文件信息,因为文件夹是在server上,所以想用批处理bat来获取该路径下所有文件信息,然后通过任务计划管理去每天自动运行bat去更新文件信息内容. 获取文件夹下所有文件 ... 
- linux常用命令--开发调试篇
			前言 Linux常用命令中有一些命令可以在开发或调试过程中起到很好的帮助作用,有些可以帮助了解或优化我们的程序,有些可以帮我们定位疑难问题.本文将简单介绍一下这些命令. 示例程序 我们用一个小程序,来 ... 
