博客
关于我
基于react hooks,antd4 配置生成表单并自动排列
阅读量:428 次
发布时间:2019-03-06

本文共 6866 字,大约阅读时间需要 22 分钟。

react后台项目,大多都是表单处理,比如下列4种常见1*n布局 (如果手工编码,大量的Row,Col, Form.Item的嵌套,排列,如果加上联动处理,代码将十分臃肿,不易维护)

  1. 一行一列

  2. 一行两列

  3. 一行三列

  4. 一行四列

对于这列表单开发, 完全可以基于配置生成, 我们可以定义一个数组,数组的每一项都是一个表单项, 对于一行一列的排列, 我们可以自上而下一行一个组件进行render , 伪代码如下

return arr.map((item, idx) => itemRender(item, idx, 24))

对于一行n列 (n=2/3/4 , 参考antd grid布局, 一行最多不超过4个表单项 )

基于24 栅格系统,可以我们计算出每个组件占用的栅格数24/n , 基于此,我们可以动态创建Grid,自上而下一行一组进行render实现一行多列布局 ,伪代码如下

const len = group.length;        const span = 24 / len;        return (          
{arr.map((item, subIndex) => itemRender(item, subIndex, span))}
);

上述 itemRender 用于render表单组件, antd4表单项通常这么写 ,一个Form.Item 包裹一个表单控件,参考如下

基于js我们可以抽离出如下配置项, 1. render什么组件,例如Input/Select/等,另外配置组件props 2. Form.Item 配置 , 我们可以设计如下通用js对象表示这些信息

{    type?: React.ComponentType | string; // 组件类型, 比如Input 等    name?: string; //Form.Item的name    label?: string; // Form.Item的label    elProps?: Record
; // 组件的props配置 , 比如type为Input, elProps则会配置到Input itemProps?: Record
; // Form.Item的props配置,除了上面name,lable,rules三个常用的,其他的可以放在这里配置 rules?: Rule[]; // Form.Item的rules};

根据上面的js对象配置信息,我们可以实现itemRender动态创建组件和布局

const itemRender = (item: Item, key: number | string, span = 24) => {  if (typeof item !== 'object' || !item) return null;  const { type, name, rules, label, elProps = {}, itemProps = {}, render, ...props } = item;  return (         
{React.createElement(type, { ...props, ...elProps } as React.Attributes)}
);};

为了更方便实现表单联动和支持render任意组件(不仅仅是表单), 我们可以扩展js加上render和getJSON 方法(当然叫getConfigJs更合适)

{    type?: React.ComponentType | string; // 组件类型, 比如Input 等    name?: string; //Form.Item的name    label?: string; // Form.Item的label    render?: () => React.ReactNode; //自定义 render    getJSON?: () => Item | null; // 动态返回Item配置    elProps?: Record
; // 组件的props配置 , 比如type为Input, elProps则会配置到Input itemProps?: Record
; // Form.Item的props配置,除了上面name,lable,rules三个常用的,其他的可以放在这里配置 rules?: Rule[]; // Form.Item的rules};

自此, 一个通用的antd form-render 就编写完了, 可以参考

安装

用 / 安装:

$ npm install --save antd-form-render$ yarn add antd-form-render

功能

  • 配置一维数组实现 1 行 n 列 (自动布局,自上向下,自左向右布局,参考汽车自动挡驾驶) n可以是1/2/3/4 ,默认1
  • 配置二维数组实现 1行n列 (手动布局,每一行显示几列根据数组长度决定,参考汽车手动挡驾驶)
  • 天然支持表单联动 ,参考下面示例1性别选择代码
  • 支持自定义render, 当antd组件无法满足需求,可以自定义返回任意react node
  • 支持动态返回js对象, 参考下面示例1性别选择代码,性别男下面动态生成输入框,女则为下拉框
  • 数据收集,name作为key ,相应表单控件的值为value

实现 1 行 1 列

import React, { useState } from 'react';import FormRender from 'antd-form-render';import { Form, Button, Space, Input, Radio, Select } from 'antd';export default function App() {  const [data, setData] = useState({});  // 定义form  const [form] = Form.useForm();  // 一维数组定义layout,从上往下一行放一个表单控件  const layout = [    {      type: Input,      label: '手机号',      placeholder: '请输入',      name: 'tel',      // 对Input的配置 , elProps对type指定的组件配置      elProps: {        maxLength: 11,      },      // 对Form.Item的配置      itemProps: {        rules: [          { required: true, message: '请输入' },          { pattern: /^1\d{10}$/, message: '手机号必须为11位数字' },        ],      },    },    {      type: Input.Password,      label: '密码',      placeholder: '请输入',      name: 'pwd',      itemProps: {        rules: [{ required: true, message: '请输入' }],      },    },    {      type: Input.Password,      label: '确认密码',      placeholder: '请输入',      name: 'confirmPwd',      itemProps: {        rules: [          { required: true, message: '请输入' },          ({ getFieldValue }) => ({            validator(_, value) {              if (!value || getFieldValue('pwd') === value) {                return Promise.resolve();              }              return Promise.reject(new Error('两次密码不一致'));            },          }),        ],      },    },    {      type: Radio.Group,      label: '性别',      name: 'gender',      elProps: {        options: [          { label: '男', value: '男' },          { label: '女', value: '女' },        ],      },    },    {      // 根据条件动态返回object      getJSON() {        return data.gender === '男'          ? {              type: Input,              label: '兴趣爱好(男)',              placeholder: '请输入兴趣爱好',              name: 'hobby',              itemProps: {                rules: [{ required: true, message: '请输入兴趣爱好' }],              },            }          : data.gender === '女'          ? {              type: Select,              label: '兴趣爱好(女)',              placeholder: '请选择兴趣爱好',              name: 'hobby',              itemProps: {                itemProps: {                  rules: [{ required: true, message: '请选择兴趣爱好' }],                },              },              elProps: {                options: [                  { label: '画画', value: '画画' },                  { label: '唱歌', value: '唱歌' },                  { label: '跳舞', value: '跳舞' },                ],              },            }          : null;      },    },    {      type: Input.TextArea,      name: 'desc',      label: '简介',      elProps: {        placeholder: '个人简介',        rows: 4,      },      itemProps: {        rules: [          {            required: true,          },        ],      },    },    {      // 自定义render      render() {        return (          
); }, }, ]; return (
{ setData((p) => ({ ...p, ...v })); }} >
);}

实现 1 行 n 列如下 ,比如一行 2 列(子数组的长度决定列数,长度能被 24 整除)

const layout = [  [    {      type: Input,      label: '11',      placeholder: '请输入',      name: '11',    },    {      type: Input,      label: '12',      placeholder: '请输入',      name: '12',    },  ],  [    {      type: Input,      label: '21',      placeholder: '请输入',      name: '21',    },    {      type: Input,      label: '22',      placeholder: '请输入',      name: '22',    },  ],];

实现 1 行 2/3/4 列如下

// 一维数组,设置了cols 为1/2/3/4 ,实现自动从左至右,从上到下的 1*cols 1行多列自动布局const layout3 = [];for (let i = 0; i < 11; i++) {  layout3.push({    type: Input,    label: `输入框${i + 1}`,    placeholder: '请输入',    name: `name${i}`,  });}
;

配置说明

// 组件export default function FormRenderer({ layoutData, cols }: FormRenderProps): React.ReactNode;// 组件propsexport declare type FormRenderProps = {    layoutData: Array
; // 1/2维数组 cols: null | 1 | 2 | 3 | 4; // 自动布局1行显示几列 default 1};// 数组配置项export declare type Item = { type?: React.ComponentType | string; // 组件类型, 比如Input 等 name?: string; //Form.Item的name label?: string; // Form.Item的label render?: () => React.ReactNode; //自定义 render getJSON?: () => Item | null; // 动态返回Item配置 elProps?: Record
; // 组件的props配置 , 比如type为Input, elProps则会配置到Input itemProps?: Record
; // Form.Item的props配置,除了上面name,lable,rules三个常用的,其他的可以放在这里配置 rules?: Rule[]; // Form.Item的rules};

运行示例, yarn start / npm start 查看 demo , 效果如下

转载地址:http://mrjyz.baihongyu.com/

你可能感兴趣的文章
41. First Missing Positive
查看>>
80. Remove Duplicates from Sorted Array II
查看>>
83. Remove Duplicates from Sorted List
查看>>
410. Split Array Largest Sum
查看>>
程序员视角:鹿晗公布恋情是如何把微博搞炸的?
查看>>
系统编程-进程间通信-无名管道
查看>>
一个支持高网络吞吐量、基于机器性能评分的TCP负载均衡器gobalan
查看>>
404 Note Found 团队会议纪要
查看>>
使用Redis作为Spring Security OAuth2的token存储
查看>>
【SOLVED】Linux使用sudo到出现输入密码提示延迟时间长
查看>>
springmvc转springboot过程中访问jsp报Whitelabel Error Page错误
查看>>
项目引入非配置的文件,打成war包后测试报错的可能原因
查看>>
Git学习笔记
查看>>
不需要爬虫也能轻松获取 unsplash 上的图片
查看>>
痞子衡嵌入式:语音处理工具pzh-speech诞生记(2)- 界面构建(wxFormBuilder3.8.0)
查看>>
痞子衡嵌入式:极易上手的可视化wxPython GUI构建工具(wxFormBuilder)
查看>>
痞子衡嵌入式:串口调试工具pzh-com诞生记(2)- 界面构建(wxFormBuilder3.8.0)
查看>>
elementUi源码解析(1)--项目结构篇
查看>>
Nmap扫描工具介绍
查看>>
算法笔记:递归、动态规划
查看>>