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 组件,主要是如何开发更适合业务场景的组件。