Based on a highly available form antd package assembly code results in reduced cv bug

introduction

Our prototype development stage in the process has many forms, antd have form components, but relatively small size, simple in terms of components, understandable, but in the development process, the code may result in insufficient aggregation, and some can not form a common logical extraction, more copy paste, it can be packaged, to engage a compatibility and scalability are fit assembly project itself.

The main idea

I simply looked up some information about the reference to other people's packages, in order to decide Coland FormItemas the basic unit, a form of construction, the main reason

  • Can FormItemthe information and Colthe way incoming information objects, the information contained so that we can focus on components to reduce CV code can cause the bug
  • ColThe layout can be adjusted, and can adjust the position occupied by the width of the form unit
  • Form component form is uncertain, it may be also possible that the input select, can be passed external, common attributes may be internally modified
  • High reusability, you can use it to achieve a pure form and submit a list of components can be combined into a search form or any other project in need of a custom form

Implementation details

AbstractFormItemInfo

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 components

 * @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>
    )

Unified Approach

  • The prompt text component type
  /**根据组件类型 给出提示文字
   * @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}`
  }

  • Generates validation rules
  // 生成验证规则
 * @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]
  • Given the unified style modified according to the type of component
  /**根据组件类型 给出统一样式修改
   * @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
  }

Note: when there is a form to display a text or a button details at this time need isDetailto get rid ofgetFieldDecorator托管

Realize submit the form 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>

To BaseFormcall the renderFormAreamethod in

// 水平和垂直布局
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}/>
  }

FormItemInfosThis is a two-dimensional array, a two-dimensional table, and each individual packet information carrier and information used here getLayOutByTypeencapsulate common horizontal and vertical layout

Here a combination of our business in the form layout headlines and subheadings to form regional grouping, I will engage in a separate layout SubmitLayOutcomponent rendering logic components and styles in which to achieve this is also easy to change into otherLayOut

// 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>

Epilogue

Follow-up also implements serachFormand other business-related components of high, so personally I think the main idea is encapsulated

  • The more pure the better underlying components
  • Middle high applicability can achieve some specific and general business component method
  • Details on specific aspects to the top of the page

Guess you like

Origin www.cnblogs.com/amigod/p/antd-form-component-rebuild.html