基于react hooks,antd4 配置生成表单并自动排列
react后台项目,大多都是表单处理,比如下列4种常见1*n布局 (如果手工编码,大量的Row,Col, Form.Item的嵌套,排列,如果加上联动处理,代码将十分臃肿,不易维护)
一行一列
一行两列
一行三列
一行四列
对于这列表单开发, 完全可以基于配置生成, 我们可以定义一个数组,数组的每一项都是一个表单项, 对于一行一列的排列, 我们可以自上而下一行一个组件进行render , 伪代码如下
return arr.map((item, idx) => itemRender(item, idx, 24))
对于一行n列 (n=2/3/4 , 参考antd grid布局, 一行最多不超过4个表单项 https://ant.design/components/grid-cn/)
基于24 栅格系统,可以我们计算出每个组件占用的栅格数24/n , 基于此,我们可以动态创建Grid,自上而下一行一组进行render实现一行多列布局 ,伪代码如下
const len = group.length;
const span = 24 / len;
return (
<Row key={idx}>
{arr.map((item, subIndex) => itemRender(item, subIndex, span))}
</Row>
);
上述 itemRender 用于render表单组件, antd4表单项通常这么写 ,一个Form.Item 包裹一个表单控件,参考如下
<Form.Item
label="Username"
name="username"
rules={[{ required: true, message: 'Please input your username!' }]}
>
<Input />
</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<string, unknown>; // 组件的props配置 , 比如type为Input, elProps则会配置到Input
itemProps?: Record<string, unknown>; // 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 (
<Col span={span} key={key}>
<Form.Item name={name} label={label} rules={rules} {...itemProps}>
{React.createElement(type, { ...props, ...elProps } as React.Attributes)}
</Form.Item>
</Col>
);
};
为了更方便实现表单联动和支持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<string, unknown>; // 组件的props配置 , 比如type为Input, elProps则会配置到Input
itemProps?: Record<string, unknown>; // Form.Item的props配置,除了上面name,lable,rules三个常用的,其他的可以放在这里配置
rules?: Rule[]; // Form.Item的rules
};
自此, 一个通用的antd form-render 就编写完了, 可以参考https://github.com/leonwgc/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 (
<Form.Item>
<Space>
<Button htmlType="submit" type="primary">
确定
</Button>
<Button htmlType="reset">重置</Button>
</Space>
</Form.Item>
);
},
},
];
return (
<Form
form={form}
onValuesChange={(v) => {
setData((p) => ({ ...p, ...v }));
}}
>
<FormRender layoutData={layout} />
</Form>
);
}
实现 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}`,
});
}
<FormRender layoutData={layout3} cols={cols}></FormRender>;
配置说明
// 组件
export default function FormRenderer({ layoutData, cols }: FormRenderProps): React.ReactNode;
// 组件props
export declare type FormRenderProps = {
layoutData: Array<Item>; // 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<string, unknown>; // 组件的props配置 , 比如type为Input, elProps则会配置到Input
itemProps?: Record<string, unknown>; // Form.Item的props配置,除了上面name,lable,rules三个常用的,其他的可以放在这里配置
rules?: Rule[]; // Form.Item的rules
};
运行示例, yarn start / npm start 查看 demo , 效果如下
基于react hooks,antd4 配置生成表单并自动排列的更多相关文章
- 基于React和Node.JS的表单录入系统的设计与实现
一.写在前面 这是一个真实的项目,项目已经过去好久了,虽然很简单,但还是有很多思考点,跟随着笔者的脚步,一起来看看吧.本文纯属虚构,涉及到的相关信息均已做虚构处理, 二.背景 人活着一定要有信仰,没有 ...
- 基于PHP和mysql的自动生成表单
开发背景:公司要求管理系统能够由管理员在前台页面管理系统表单,能够对表单进行增删改查基本操作,表单的各个字段都可以被修改.删除,可以添加新的字段,并且不影响系统正常运行,前台表单展示要由系统自动处理, ...
- Swift3.0服务端开发(二) 静态文件添加、路由配置以及表单提交
今天博客中就来聊一下Perfect框架的静态文件的添加与访问,路由的配置以及表单的提交.虽然官网上有聊静态文件的访问的部分,但是在使用Perfect框架来访问静态文件时还是有些点需要注意的,这些关键点 ...
- vue自定义表单生成器,可根据json参数动态生成表单
介绍 form-create 是一个可以通过 JSON 生成具有动态渲染.数据收集.验证和提交功能的表单生成器.并且支持生成任何 Vue 组件.结合内置17种常用表单组件和自定义组件,再复杂的表单都可 ...
- yii2自动生成表单
视图中: 1.要use的两个文件类 use yii\helpers\Html; use yii\widgets\ActiveForm; 2.生成表单,以添加商品为例说明.注意红线区域:上传文件需要 ...
- 表单组件 form fastadmin(生成表单元素)
Form组件 定义文件位置: /extend/fast/Formphp 通用参数 $name 通常为我们组件的名称(name属性值),我们在后台接收时可以通过这个名称来获取到它所对应的值 $value ...
- 基于jQuery会员中心安全修改表单代码
基于jQuery会员中心安全修改表单代码.这是一款登录密码,交易密码,手机号码,实名认证,电子邮箱,安全设置表单,会员表单等设置代码.效果图如下: 在线预览 源码下载 实现的代码. html代码: ...
- 一款基于jquery ui的动画提交表单
今天要给大家分享一款基于jquery ui的动画提交表单.这款提交表单的的效果是以动画的形式依次列表所需填写的信息.效果非常不错,效果图如下: 在线预览 源码下载 实现的代码. html代码: & ...
- java自动生成表单简单实例
数据库表设置 tb_form(form表单) 字段 类型 约束 说明 Id Int 主键 主键 Formid Varchar2(20) 唯一 Form表单id的值 Action Varchar2(20 ...
随机推荐
- rest framework ViewSet
ViewSets 路由选择确定要用于一个请求哪个控制器之后,控制器负责做出请求的感并产生相应的输出. - Ruby on Rails的文档 Django的REST框架允许你的逻辑一组在一个类中的相关意 ...
- FreeBSD 入门 哲学与玄学
『哲学与玄学』 FreeBSD 是一种 UNIX 哲学(如模块化,一切皆文件等,见< UNIX 编程艺术>❩的发展,也是学院派的代表作品.她是一套工具集,她存在目的是为了让人们更好的生活. ...
- 【java框架】MyBatis-Plus(1)--MyBatis-Plus快速上手开发及核心功能体验
1.MyBatis-Plus入门开发及配置 1.1.MyBatis-Plus简介 MyBatis-Plus(简称 MP)是一个 MyBatis的增强工具,在 MyBatis 的基础上只做增强不做改变, ...
- springboot 配置文件application
application.properties # ----------------------------------------# 核心属性# --------------------------- ...
- 【LiteOS】LiteOS任务篇-源码分析-创建任务函数
目录 前言 链接 参考 笔录草稿 部分源码分析 源码分析 LOS_TaskCreate函数 LOS_TaskCreateOnly函数 宏 OS_TCB_FROM_PENDLIST 和 宏 LOS_DL ...
- python多版本与虚拟环境
这篇纯python技术文章,我自己平时也会用到,在此记录一下. 为什么会用到多个Python版本? 用macOS和Ubutntu的同学都知道系统默认安装的Python2.7.x,然后,我们平时pyth ...
- elasticsearch 7.7 配置文件:elasticsearch.yml
# ======================== Elasticsearch Configuration ========================= # # NOTE: Elasticse ...
- Oracle 存储结构
数据库是存储数据的容器,它的主要功能是保存和共享数据. oracle数据库的存储结构可以分为逻辑存储结构和物理存储结构,对于这两种存储结构,oracle是分别进行管理的. 逻辑存储结构:oracle内 ...
- 学习笔记-angular 使用uuid
import { UUID } from 'angular2-uuid'; let uuid = UUID.UUID().replace(/-/g, '').toLocaleUpperCase(); ...
- Throwing cards away I UVA - 10935
Given is an ordered deck of n cards numbered 1 to n with card 1 at the top and card n at the botto ...