基于antd封装一个高可用form组件 减少cv代码导致的bug
引言
在开发中台过程中 我们的原型中有很多表单,antd有表单组件,但是粒度比较细,就单纯组件而言,无可厚非,但是在开发过程中,可能会造成代码不够聚合,有些表单公共逻辑无法提取,copy paste比较多,所以可以加以封装,搞一个兼容性和扩展性都契合项目本身的组件。
主要思路
我简单查阅了一番资料,参考了一下别人的封装方式,决定以Col和FormItem作为基本单元,进行表单的搭建,主要原因
- 可以将
FormItem的信息和Col的信息以对象方式传入,这样我们可以更加专注于组件的包含的信息 减少CV代码可能导致的bug Col可以进行布局的调整,可以调整表单单元位置和所占宽度- 表单的组件形式是不定的,可能是input也有可能是select,所以可以进行外部传入,通用属性可以内部修改
- 复用性高,可以用它来实现一个纯提交表单 和列表组件结合成可搜索表单 或者其他任何项目里需要自定义的一个表单
实现细节
抽象的FormItemInfo
export interface FormItemInfo {
name: string, //label
id: string, // 属性
colLayOut?: object,// 列布局
formItemLayout?: object,// 表单项布局
Comp?: any, // 传入的组件 不传默认input
ruleArr?: RuleObj[],// 验证规则
initialValue?: string, // 初始值
required?: boolean, // 是否必填
CompExtraProps?: object // 传入组件额外属性
isDetail?: boolean //是否需要被getFieldDecorator托管
}
baseForm组件
* @param name 表单项label
* @param id 属性字段名
* @param colLayOut 列布局
* @param formItemLayout 表单项布局
* @param Comp 传入的组件 不传默认input
* @param ruleArr 验证规则 长度只需传入{max:xxx}验证信息是统一的
* @param initialValue 初始值 编辑时推荐使用antd的mapPropsToFields 不要手动设置回显值
* @param required 是否必填 默认否 因为要统一写验证提示
* @param CompExtraProps 组件额外属性
const mapToFormItem = (val: FormItemInfo) => {
......
// 是否传入组件
const hasCompType = Comp && Comp.type
// 根据组件类型 给出提示文字
const msg = getMsgByCompType(hasCompType && hasCompType.name, name)
// 判断是不是select组件 是的话 调整宽度样式
const mixStyle = fixStyleByCompType(hasCompType && hasCompType.name)
// 生成验证规则
const rules = getFormRules(ruleArr || [], required || false, name)
return (
<Col {...(colLayOut || defaultColSpan)} key={id}>
{!isDetail ?
<FormItem label={name} key={id} {...(formItemLayout || {})}>
{/*用cloneElement方法给传入的组件加新属性*/}
{
getFieldDecorator(id, {
initialValue: initialValue || '',
rules,
})(Comp ? React.cloneElement(Comp, { placeholder: msg, ...mixStyle, ...CompExtraProps }) : <Input type="text" placeholder={msg}/>)
}
</FormItem> : <FormItem label={name} key={id} {...(formItemLayout || {})}> {Comp}</FormItem>}
</Col>
)
}
统一方法
- 根据组件类型 给出提示文字
/**根据组件类型 给出提示文字
* @param type 组件类型 根据传入组件的函数名判断 在map里维护
* @param name label名称
* @returns 提示文字
* */
const getMsgByCompType = (name: string, type?: string): string => {
if (!type) {
return `请输入${name}`
}
const map: { [props: string]: string } = {
Select: '请选择',
Input: '请输入',
default: '请输入',
}
return `${map[type] || map.default}${name}`
}
- 生成验证规则
// 生成验证规则
* @param ruleArr 验证规则 长度只需传入{max:xxx}验证信息是统一的
* @param name 表单项label
* @param required 是否必填 默认否 因为要统一写验证提示
const getFormRules = (val: RuleObj[], required: boolean, name: string) => {
// 根据max生成最长输入提示
const ruleArr: object[] = []
val.forEach(item => {
if ('max' in item) {
ruleArr.push({ ...item, message: `输入信息不能超过${item.max}字` })
} else {
ruleArr.push(item)
}
})
// 根据name生成报错提示
return [{ required: required, message: `${name}不能为空` }, ...ruleArr]
- 根据组件类型 给出统一样式修改
/**根据组件类型 给出统一样式修改
* @param type 组件类型 根据传入组件的函数名判断 在map里维护
* @returns 样式对象
* */
const fixStyleByCompType = (type?: string): object => {
if (!type) {
return {}
}
const map: { [props: string]: object } = {
Select: { style: { width: '100%' } },
default: {},
}
return map[type] || map.default
}
注意:当出现表单显示一个详情文字或者一个按钮 此时需要用isDetail干掉getFieldDecorator托管
实现提交表单SubmitForm
* @param form -`antd`的form
* @param title - 主标题
* @param subTitle - 分组标题
* @param FormItemInfos - 二维数组 顺序和数量和分组标题对应 存放表单项信息
* @param isLoading - `dva-loading` 执行effects过程中的loading
* @param onSubmit - 传入的submit方法
* @param buttonArea - 可选 不传默认数提交和取消 传入覆盖
* @param children - 在表单下面 按钮区域上面的传入内容
* @param formLayOutType - 布局方式 详情见`getLayOutByType`方法
* @returns ReactNode
......
<Form onSubmit={onSubmit}>
<SubmitLayOut subTitle={subTitle} title={title} renderFormArea={renderFormArea}>
{children}
{buttonArea?buttonArea: <Row type="flex" gutter={24} justify="center">
<Col>
<Button type="primary" htmlType="submit" loading={isLoading}>提交</Button>
</Col>
<Col>
<Button type="default" onClick={() => router.go(-1)}>取消</Button>
</Col>
</Row>}
</SubmitLayOut>
</Form>
对BaseForm的调用在renderFormArea方法里
// 水平和垂直布局
export enum FormLayOutType {
normal = 'normal',
vertical = 'vertical'
}
const renderFormArea = (idx: number) => {
// 在这边加上normal表单的layout
const FormItemInfo = FormItemInfos[idx]
// 根据传入参数 返回布局类型
const _FormItemInfo = getLayOutByType(formLayOutType||FormLayOutType.normal, FormItemInfo)
return <BaseForm formItems={_FormItemInfo} form={form}/>
}
FormItemInfos这里是二维数组,二维分别承载分组信息和表单项信息 而且在这里用getLayOutByType封装常用的水平 垂直布局方式
这里结合了我们业务里的表单布局 大标题 和小标题对表单区域进行分组,我将布局单独搞了个SubmitLayOut组件 将渲染逻辑和样式组件在其中实现 这样也方便更换成其他LayOut
// SubmitLayOut
* @param title - 主标题
* @param subTitle - 分组标题
* @param renderFormArea - 根据分组的顺序 渲染表单区域
* @param children - 传入内容
......
<Card title={title} bordered={false} className={styles["special-card"]}>
<List itemLayout="vertical" className="special-list">
{subTitle.map((item,idx) => {
return (
<>
<Meta title={item}/>
<List.Item>
{renderFormArea(idx)}
</List.Item>
</>
)
})}
</List>
{children}
</Card>
结语
后续还实现了serachForm等业务相关性高的组件,所以个人觉得封装的思路主要是
- 底层组件越纯粹越好
- 中层可以实现一些适用性比较高的具体业务组件和通用方法
- 高层就具体要页面的细节的方方面面了
基于antd封装一个高可用form组件 减少cv代码导致的bug的更多相关文章
- 基于iview 封装一个vue 表格分页组件
iview 是一个支持中大型项目的后台管理系统ui组件库,相对于一个后台管理系统的表格来说分页十分常见的 iview是一个基于vue的ui组件库,其中的iview-admin是一个已经为我们搭好的后天 ...
- 如何基于 React 封装一个组件
如何基于 React 封装一个组件 前言 很多小伙伴在第一次尝试封装组件时会和我一样碰到许多问题,比如人家的组件会有 color 属性,我们在使用组件时传入组件文档中说明的属性值如 primary , ...
- 基于Containerd安装部署高可用Kubernetes集群
转载自:https://blog.weiyigeek.top/2021/7-30-623.html 简述 Kubernetes(后续简称k8s)是 Google(2014年6月) 开源的一个容器编排引 ...
- SpringCloud学习系列之一 ----- 搭建一个高可用的注册中心(Eureka)
前言 本篇主要介绍的是SpringCloud相关知识.微服务架构以及搭建一个高可用的服务注册与发现的服务模块(Eureka). SpringCloud介绍 Spring Cloud是在Spring B ...
- 美团点评基于MGR的CMDB高可用架构搭建之路【转】
王志朋 美团点评DBA 曾在京东金融担任DBA,目前就职于美团点评,主要负责金融业务线数据库及基础组件数据库的运维. MySQL Group Replication(以下简称MGR),于5.7.17版 ...
- 如何安装一个高可用K3s集群?
作者介绍 Janakiram MSV是Janakiram & Associates的首席分析师,也是国际信息技术学院的兼职教师.他也是Google Qualified Developer.亚马 ...
- 阿里云有奖体验:用PolarDB-X搭建一个高可用系统
体验简介 场景将提供一台配置了CentOS 8.5操作系统和安装部署PolarDB-X集群的ECS实例(云服务器).通过本教程的操作,带您体验如何使用PolarDB-X搭建一个高可用系统,通过直接ki ...
- 微服务配置内容《网上copy》=========》如何创建一个高可用的服务注册中心
前言:首先要知道什么是一个高可用的服务注册中心,基于spring boot建成的服务注册中心是一个单节点的服务注册中心,这样一旦发生了故障,那么整个服务就会瘫痪,所以我们需要一个高可用的服务注册中心, ...
- 基于Consul的数据库高可用架构【转】
几个月没有更新博客了,已经长草了,特意来除草.本次主要分享如何利用consul来实现redis以及mysql的高可用.以前的公司mysql是单机单实例,高可用MHA加vip就能搞定,新公司mysql是 ...
随机推荐
- GitHub_Hexo_Next 搭建博客
利用最新版本的 hexo+next 重构了个人博客,下面简单记录了搭建博客的完整过程: 一.环境准备 1.安装 Node.js 2.安装 Git 3.注册 Github 账号 二.在GitHub上创建 ...
- 使用Typescript重构axios(二十九)——添加baseURL
0. 系列文章 1.使用Typescript重构axios(一)--写在最前面 2.使用Typescript重构axios(二)--项目起手,跑通流程 3.使用Typescript重构axios(三) ...
- nsq (三) 消息传输的可靠性和持久化[二]diskqueue
上一篇主要说了一下nsq是如何保证消息被消费端成功消费,大概提了一下消息的持久化,--mem-queue-size 设置为 0,所有的消息将会存储到磁盘. 总有人说nsq的持久化问题,消除疑虑的方法就 ...
- Jquery EasyUI 中ValidateBox验证框使用讲解
来源素文宅博客:http://blog.yoodb.com/ Validatebox(验证框)的设计目的是为了验证输入的表单字段是否有效.如果用户输入了无效的值,它将会更改输入框的背景颜色,并且显示警 ...
- 关于find的-perm
关于find的-perm 参考关于find命令-perm 的用法 总结 有三种用法 find -perm -mode find -perm mode find -perm /mode(find -pe ...
- springboot返回统一接口与统一异常处理
springboot返回统一接口与统一异常处理 编写人员:yls 编写时间:2019-9-19 0001-springboot返回统一接口与统一异常处理 简介 创建统一的返回格式 Result 封装统 ...
- GitHub和Git
GitHub托管项目代码 首先一些基本概念: repository(仓库) 用来存放项目代码,每个项目代表一个仓库,开一个项目就意味着你有一个仓库. star(收藏) 收藏方便下次查找. fork(复 ...
- SqlServer2005 查询 第七讲 order by
今天我们来讲sql命令中的参数order by的用法 order by order by:可以理解成[以某个字段排序] order by a,b // a和b都按升序 order by a,b des ...
- 通过javascript 执行环境理解她
古往今来最难的学的武功(javascript)算其一. 欲练此功必先自宫,愿少侠习的此功,笑傲江湖. 你将了解 执行栈(Execution stack) 执行上下文(Execution Context ...
- VMware安装Ubuntu 16.04.4 LTS
1.下载Ubuntu镜像 https://www.ubuntu.com/download/desktop 2.创建新的虚拟机 3. 4.这里默认即可,可以不选 5. 6. 7.这里位置可以随时改 8. ...