0.0.6 • Published 5 years ago

@jzl/aa-form v0.0.6

Weekly downloads
6
License
MIT
Repository
-
Last release
5 years ago

auto-antd-form

起因

Form 使用双向绑定,开发效率高,代码可读性好。

  1. 双向绑定表达,表达简单直观。支持嵌套字段

  2. 提供 validate 机制,配合 <FormContext><FormButton>, 自动管理相关状态。

  3. 组件使用方式和 antd 一致,几乎没有学习成本,可以直接参考 antd 的文档。

  4. 扩展性强,符合 value,onChange 模式的组件,通过简单的包装,可以快速融入进这套模式中

  5. 性能。每次修改,只有被编辑的那个组件会触发渲染,form 再大,也不会有性能问题。

使用

  1. 首先安装 react react-dom immer -react antd
  2. yarn add @jzl/aa-form
  3. 如果使用 antd 的按需加载,为了样式生效,需要在 webpack 的 modules 的 rules 中 配置添加
  {
    test: /node_modules[\\/]@jzl[\\/]aa-form[\\/].*\.(j|t)sx?$/,
    use: {
      loader: "babel-loader",
      options: {
        // your options
      }
    }
  },

Basic Usage

import { FormContext, FormInput, FormCheckbox } from '@jzl/aa-form';

// function component
return (
  <FormContext
    initState={{
      text: '',
      done: false,
    }}
  >
    <FormInput
      className="input-class"
      label="text"
      path="text"
      rules={(value: string) => {
        // return 非空字符串表示验证有错误,提示就是这个字符串
        if (value === 'todo') {
          return '不能输入 todo';
        }
      }}
      placeholder="输入todo文本"
    />
    <FormCheckbox label="done" path="done" />
  </FormContext>
);

一个复杂的例子

demo

FormContext

// 使用 state 为受控模式,需要在 onContextChange 对state 进行更新
// 传入state后,会忽略 initState
{
  initState?: M;
  state?: M;
  validateAtFirst?: boolean; // 默认是点击过 FormButton 后才开始做validate 检查,如果开始就要检查,设置为true
  onSubmit({ state }: { state: M }, e: React.FormEvent<HTMLFormElement>): void; // 只有 validate 检查成功后,才会触发
  onContextChange?({ state }: { state: M }): void; // 这个form的state,有任何的改变
}

提供的组件和设施 (待添加)

  1. 组件
FormInput, FormTextArea,FormInputNumber

FormCheckbox

FormSelect, FormRadioGroup, FormTagGroup

FormDate, FormDateRange
  1. 设施
// 下面两个用于提供上下文(公共model),状态的检验和 submit 事件等
FormContext: 提供共享上下文,比如 model(如果组件提供的 model,优先级更改), 一些通用样式,比如 label 占多宽

FormButton: 和 FormContext 配合,自动管理验证和提交

FormWrapper: 自定义复杂类型,比如需要动态修改的数组,Map。请参考本文档的 `一个复杂的例子`.

API

From 组件,如 Input, Select, Radio 等,

export type ValidateFn<M> = ((value: any, model: M) => string | void) | string;

export interface ICommonOption {
  key?: string;
  title: string;
  value: any;
}
// 通用属性如下
// 一般情况,你只需要关注2,3个属性
{
  path?: string; // 字段名
  onChange?(param: IChangeParam<M>): void; // onChange 事件,此时 value 已经修改
  beforeChange?(
    param: IChangeParam<M> & {
      oldValue?: any;
    },
  ): boolean | void; // change 发生前,可以拿到 old value. 函数return false, 阻止修改
  transformViewToModel?(value: any, props: ICommonFormOuterProps<M>): any;
  transformModelToView?(mValue: any, props: ICommonFormOuterProps<M>): any;
  label?: string | React.ReactNode;
  itemProps?: FormItemProps; // antd Form.Item 的 props
  noFormItem?: boolean; // 默认所以的组件都会包裹在 <Form.Item>里,设置 true,直接返回组件
  rules?: ValidateFn<M> | ValidateFn<M>[]; // validate 规则
  suffixTip?: React.ReactNode; // 组件后面的提示文案
  [x: string]: any; // 其他组件属性
}

FormWrapper 要求 children 是一个函数,函数的参数如下 model 定义如下

export type IAaFormModel<M> = {
  state: M; // 最新的 state
  setKey(key: string, value: any): M; // 修改某一个字段,返回新的 state
  update(updateFn: (draft: Draft<M>) => void): M; // 包装了 immer 的produce,在函数里直接修改 state,返回新的 state
};

Validate

在组件上添加 rules 接受 (value: any, Model: M) => string | any 返回值只要是非空字符串,就表明出错,提示信息就是返回的字符串

// yourRuleFn 接受 value, 以及 state: M, 通过这两个
// 返回值只要是非空字符串,就表明出错,
<FormInput path="text" rules={yourRuleFn} />

点击按钮后,检查所有规则,如果有错,阻止提交,给出提示(提示的样式见 antd Form.Item) 同时 disable FormButton,直到满足所有规则。

组件可以自己提供 defaultRuleFn: (value, model) => string | any 通过 defaultRuleFn 去控制状态默认的的合法性,比如上传组件,正在上传中,最近的状态不是合法的,可以设置为 请等待上传完毕

对 Antd 的修改

  1. 统一 onChange 的参数(antd 中 Input 传的是 Event,CheckBox 传的 checked value)。不过双向绑定的机制,几乎不需要关注 onChange 方法。
  2. FormDate 默认的 value 是时间戳,为 number 类型,13 位数字。传入 unix={true} value 是 10 位数字。
  3. label 直接设置,其他 Antd 的 Form.Item 的属性,通过 itemProps 传入, 具体见antd 文档
  4. 所有接受选项的组件,统一成传入 options 数组, 每一项提供 title 和 value { title: string, value: number|string }, 便于生成代码生成
  <FormInput label="input label" itemProps={...customItemProps}>

value 的取值规则

  1. 默认 _.get(mode, path) (path 支持嵌套)
  2. 组件提供,比如 FormDateFormDateRange 会把 antd 返回的 moment 改为 timestamp
function FormDate(props: IFormComponentProps) {// ...}
FormDate.transformModelToView = function(timestamp: number, props: IProps) {
  // 把model上的value,转成antd 需要的moment
};

FormDate.transformViewToModel = function(momentInst: Moment, props: IProps) {
  // 把 antd 组件的 moment 转成时间戳
};
  1. 使用组件时传入transformModelToViewtransformViewToModel

上面 3 个规则,优先级越来越高。

自定义

只要符合 value, onChange 模式的组件,可以快速融入这套体系,比如基于react-color的改造,只需要下面几行代码。

import * as React from 'react';
import { FormRender } from '@jzl/auto-form';
import { SketchPicker, ColorResult } from 'react-color';
import { IRenderProps } from '@jzl/auto-form/lib/form-render';
import { ICommonFormOuterProps } from '@jzl/auto-form/lib/types';

export function FormColor<M>(rawProps: ICommonFormOuterProps<M>) {
  return (
    <FormRender
      {...rawProps}
      render={(props: IRenderProps<M>) => {
        function handleChange(e: ColorResult) {
          props.onChange(e.hex);
        }
        return (
          <SketchPicker onChangeComplete={handleChange} color={props.value} />
        );
      }}
    ></FormRender>
  );
}