Socket
Book a DemoInstallSign in
Socket

@amazebird/schme-form

Package Overview
Dependencies
Maintainers
1
Versions
1
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@amazebird/schme-form

0.0.1
latest
npmnpm
Version published
Weekly downloads
1
Maintainers
1
Weekly downloads
 
Created
Source

表单引擎使用说明

简述

表单是后台管理最常遇到的一种数据管理模式,在管理系统中被大量使用,但是在react中,表单的开发却相对比较复杂,需要绑定数据源, 需要去写大量的模版代码来定义每一个Field内容,包括不同的应用场景:新增,修改,查看,以及表单之间存在复杂的关联操作,联动规则,造成表单开发的工作量较大, 影响项目的开发效率。复杂的业务关联也容易使代码间的耦合关系复杂,造成可读性差与难以维护性。 表单组件提供一种相对简易的方式来开发对应的表单功能,通过配置化的方式简化表单开发。使用

表单组件提供的功能包括:

  • 表单组件提供了:新增,修改,查看三种模式,只需设置参数mode,不需要再进行额外处理
  • 界面布局:表单组件提供了一套标准的界面布局,但如果需要个性化,表单组件自身也提供了默认展现模式

TODO 待办事务

  • 去除内置组件,包装组件由业务场景直接引用包装组件,以提供后期性能优化支持
  • 增加对于数组表单的支持
  • 增加对对象字段的支持
  • 注册组件环节太长,需要优化
  • formCard默认给子元素包裹了row,当FormItem visible=none时,占位仍然存在 ———— 不处理,业务方自已解决
  • 需要增加验证中的type,whitespace的设置
  • 增加对rules的支持,以满足对于错误提示信息的自定义
  • 增加 name 属性,用于相关提示信息的显示
  • 增加'text'属性,用于设定字段以文本形式显示
  • 增加trigger, 可以设置field对外部属性的监听,从而实现外部对field的影响
  • 增加对修改模式,详情模式的支持
  • 增加format属性,对data的初始化格式处理
  • FormItem使用class实现,通过shouldComponentUpdate进行性能优化
  • ValueChange进行节流处理,以避免类似input框连续输入造成大量渲染的情况 -- 最终是在FormItem中,对changeFieldValue的节流实现
  • 需要考虑多处对同一个value进行修改时的情况
  • 增加reset功能 —— reset应该是返回到初始状态,form的reset是清空所有form的值,需要调整
  • 将schema中每个属性的配置进行独立封装,提升可读性,方便维护
  • 保留component 各个模式的对应配置,当mode改变时,不需要重新对schema进行初始化
  • FormButton增加visible方法支持
  • FormButton增加自定义展现支持
  • mobile增加错误信息显示组件
  • Item增加index属性,支持数组的个性化处理
  • 增加propsType,对参数进行基础验证
  • defaultValue不会触发onFieldChange,因此在init时的 formData中无法获取到defaultValue的值,需要对init的formData进行一个合并
  • component去除模式分类,仅通过observer来进行处理,以减少概念
  • output支持全场景下的处理? —— 需要考虑一下
  • keepAlive支持全局默认设置
  • 支持子字段继承父级字段设置,
  • Parent增加repeat属性,声明是否需要遍历

shema

shema 是表单组件的配置项,通过对shema的配置,可以动态生成对应的表单,配置的内容为表单中包含哪些字段,每个字段的验证规则等内容

  const schema = {
      "userName":{
        label:'用户名', 
        placeholder:'请填写用户名', 
        component:'input',
        disabled:false, 
        visible:false,
        keepAlive:true,
        options: [],
        rules:{
          required:[true,'请填写用户名称'],  // 是否必填
          pattern:^[A-Za-z\d]+([-_.][A-Za-z\d]+)*@([A-Za-z\d]+[-.])+[A-Za-z\d]{2,4}$ //正则
          max:50,             // 最大长度/数量
          min:10,             // 最小长度/数量
          validator: ({ value, formData })=>{ // 自定义验证方法,用于处理业务化的验证规则, 如果 required, max, min, pattern 不能满足验证需求时,可以自定义validator
          const {startTime,endTime} = formData
          if(startTime > endTime) return '开始时间不能大于结束时间'
          },
          ...
        },
        observer:{
          watch:'firstName',                   
          action: (firstName)=>{
            return {value:`${newValue}=1111`}
          }
        },
        props:{
          className:'user-name'
        }
      },
      "firstName":{
        label:'姓氏',
        component:'input'
        ...
      }
    ]


SchemaForm的使用

SchemaForm是表单引擎的主组件,SchemaForm将根据定义好的schema自动生成对应的表单

SchemaForm的主要属性包括:

属性说明可选参数默认
schema表单配置----
data表单实体对象,用于初始化表单数据--
mode表单模式add(新增)/modify(修改)/detail(详情)add
trigger将组件的props/state注册为trigger,在schema中可以通过observer来监听trigger的变动,实现与props/state的联动----

field配置:

属性说明类型默认支持初始化支持联动
label用于在表单上显示的字段名string | react element------
component表单字段所使用的组件, 支持stringcomponent两种类型,string为当前表单引擎提供的内置的field组件类型,例如:'input' ,同时也支持component为用户自定义组件(详见“自定义表单组件”)string | component------
placeholder占位文本,与input等组件配合使用string------
disabled是否禁用操作boolean | function | objectfalsetruetrue
visible是否显示当前字段boolean | function | objecttruetruetrue
value设置当前字段的值
value不支持直接赋值,只支持初始化方法和监听
但要注意避免产生循环监听,循环监听可能产生死循环
例如:A监听b,c监听a,b监听c,这时当b值改变时,可能造成死循环
function | object--truetrue
keepAlive当字段处于不可见状态时,是否保持field的value。将keepAlive设置为false时,当字段不可见时,该字段的value将会丢失booleantrue----
options适用于选择相关组件的可选项处理 ,例如:select, radio,picker, cascader 等array | function | object[]truetrue
format如果你需要对表单的输入(input),输出值(output)进行格式化的话,可以使用format
input仅支持function
output支持functionfalse
outputfalse时,会从formdata中删除该feild,当一个field主要的作用只是参与表单联动与交互的中间值,并不需要提交时,可以使用该方式
inputoutput只在数据初始化与表单onSubmit时才会处理
{input:[function(value)],output:[function(value)| false ]}------
defaultValue默认值any------
rules字段验证,支持rc-form中的所有验证类型,但简化了设置方式:function | objecttruetruetrue
name用于给rules提供默认的错误提示语,以简化rules的配置
例如:当name用户名,只设置了{required:true}时,其对应的默认错误提示为请填写用户名
如果设置了label时,name会默认取label的值作为自身的值
string------
type如果表单字段存在层级结构时,父级字段需要设置type类型是对象object还是数组array,SchemaForm会根据父字段类型对其子字段进行相应处理string ("object" | "array")------
fields如果表单字段存在层级结构时,fields用于配置对应的子字段object------
field层级结构中存一种特殊情况,数组字段下的item并不是一个对象,而是一个基础类型,这个时需要配置field以便进行区分object------
observerobserver 属性用于字段连动,当其他的联动字段无法满足业务需求时,observer提供最强大的联动能力,除了key,component等特殊属性以外,几乎能够修改任意属性{watch:[array],action:[function]}------
propsprops的属性都会直接透传给对应的 field 组件,以满足不同组件的个性化属性需要object{}truetrue

初始化与监听

初始化:field的某个属性可能并不是一开始就明确的,可能需要通过调用接口来确定它的值,这时可以使用初始化方法来动态对属性进行赋值,初始化方法支持异步,但初始化方法仅在表单初始化时执行一次。

监听:表单中很多场景下需要字段间的联动,这时可以使用监听方式对field的属性进行赋值

示例:


const schema = {
  "courseType":{
    label:"课程类型",
    component:"select",
    ...
  },
  "studentType":{
    label:"学生类型",
    ...
  },
  "course":{
    label:"课程",
    component:"select",
    options:async ({formData})=>{  // 根据课程类型对课程进行初始化
      const courseItems = await request.get('/courses',{courseType:formData.courseType})
    },
    visible:{
      watch:["studentType"],
      action:(studentType)=>{
        return studentType === 1   // 当学生类型为1时,才显示课程
      }
    }
  }

}

关于mode

在很多场景下,添加页、修改页、详情页,在布局上,字段上,是十分类似的,仅存在一些小的差异,例如在修改页中某些字段不能修改,在详情页中,字段都是以文本的形式展现等。在这样的场景下,通过mode,我们只需要针对不同模式的差异点对每个字段进行配置,就可以便捷地实现添加,修改,详情这三个功能。 默认情况下,内置组件会根据mode选择合适的展示组件。 如果默认方式无法满足你的需求,还可以选择通过观察模式observer来根据实际业务情况,自定义要展现的组件。 如果是自定义组件,那就需要开发者自己在组件中,根据mode来自行处理组件的展现。 当然,你也可以将观察模式与自定义组件结合起来使用。

示例:

trigger

有时候,字段的变动可能不完全通过表单的值产生联动,而依赖于业务组件中的属性或者内部状态,这时我们就需要用到trigger,trigger可以使SchemaForm的字段可以监听到组件中的属性或状态。 当该trigger属性发生变动时,就可以触发对应的action方法,改变field的形态。对于trigger的监听在watch的声明时需要以"*"作为前缀,以表示当前监听的是trigger,因此为了避免产生不可预期的错误,请注意不要将字段的key值以"*"作为前缀.

个性化布局

个性化布局模式支持对表单布局的自定义,包括可以增加一些卡片,对字段位置的设定,增加一些装饰元素等


export default class FormDemo extends Component {
  render() {
    return (
      <SchemaForm schema={schema} data={data} mode={FORM_MODE.MODIFY}>
        <FormCard title="基础信息" >         // FormCard 是表单卡片容器
          <Item field="userName" />                   // 通过FormItem 设置当前位置要展现的表单字段, fields定义要显示的字段
          <Item field='password' />
          <Item field='realName' />
          <Item field='phone' />
          <Item field='phoneList' />
        </FormCard>
        <Row>                         // 也可以随意表单的布局结构与字段位置
          <Item field='area' {...this.props} />
        </Row>
      </SchemaForm>
    )
  }
}

数据层级结构

内置field组件

表单组件中内置了许多其于antd的内置组件,内置组件是在antd组件的基础上,增加了Form.Item绑定,以及form.getFieldDecorator的包装 当前支持的组件有(持续增加中):

组件说明
input输入框
DatePicker日期选择器
TimePicker时间选择器
Radio单选框
Select下拉选择框
TextArea文本框

自定义表单组件

除了上面表单引擎内置的组件外,表单引擎还提供对自定义组件的支持,以满足不同业务场景的需要。 表单引擎会把所有相关属性与方法传递组自定义组件,主要属性与方法有:

属性/方法说明
form表单对象
mode当前表单模式
field当前字段配置
value当前字段值
onChange当修改了字段值时,通过调用onchange方法将最新的字段值提交给表单,在onChange方法中将自动调用validator对字段值进行校验
其他属性与方法

export default class PhoneList extends React.Component {
  render () {
    const { value, onChange } = this.props
    const _add = () =>{
      onChange([...value, '111111111'])
    }
    const _decrease = () =>{
      const newValue = [...value]
      newValue.pop()
      onChange(newValue)
    }
    return (
        <div>
          <div>{
            value && value.map(phone => <div>{phone}</div>)
          }
          </div>
          <Button onClick={_add}>添加</Button>
          <Button onClick={_decrease}>减少</Button>
        </div>
    )
  }
}

嵌套字段

嵌套字段是表单中比较复杂的情况,例如表单某个字段是一个对象,对象中的每个属性需要单独渲染, 再例如表单某个字段是一个数组,数组中可能是对象,也可能是string。也可能对象中嵌套数组,数组中又嵌套对象……==! 总的来说,嵌套字段存在两种型式:对象字段,数组字段

FormButton

属性/方法类型默认值说明
labelstring按钮显示文本
onClickfunction(formData,form )如果设置了validate, 则需要通过验证才会触发onClick方法
validateboolean/array[fieldnames]false是否需要验证
为true时,表单会先对formData进行验证,验证通过了才会触发onClick方法
onErrorfunction(errors)只有设置了validate,onError才会生效
debounceboolean/numberfalse设置按钮的节流
-boolean:debounce为true时,将默认为500ms
-number:当debounce为number时,将会以debounce的value将会作为节流时长
visiblefunction(formData,mode)返回false则隐藏该按钮,返回true则显示
resetbooleanfalse设置了reset后,点击按钮会重置表单
rendercomponent自定义Button
...其他属性与 Button 组件属性一致,如果设置了render,则需要开发者自行处理

数组字段

表单中的数组与其他单一字段不同,数组字段是需要循环遍历渲染。

Observer

action(changeValue,{})

不建议在多个observer中对同一个属性进行修改,因为observer的执行顺利并不确定。

schema规则

  • 字段没有定义component属性时,不能够被FormItem组件渲染
  • 父字段,例如 类型为 object|array 的字段,当其只作为容器时,可使用ParentItem组件对其子字段进行包裹。只作为容器的父字段可以不设置component属性。
  • 嵌套字段在监听时,只能够监听同级域或父级字段

value

value的联动是相对比较复杂的问题,由于通过父节点也能更改子节点的value值,所以就存在多处对同一个field的value进行修改的可能性。 为了避免造成逻辑上的不确定性,请确保只存在一处对value的的联动修改。

与其他表单引擎比较

### 与UForm比较 UForm采用了rxjs实现事件分发,事件的指向性更强,有更强的针对性,以提升渲染性能,减少不必要的组件渲染。 UForm的问题:

  • rxjs带来了额外的学习成本,除了rxjs外,UForm本身也增加了许多概念,如$, 事件,fieldState 等
  • 对于联动的设置都集中在 effects 属性中,而且对于某个field变动的监听操作都是集中的,如果联动涉及的字段较多,联动处理复杂,不仅会造成 effects非常庞大,使这些复杂的业务代码混杂在一起,容易显得杂乱,不清晰,难维护。

FAQ

  • 内置组件有内置对应的format,例如timePicker,但是如果component本身并不是明确的,是基于observer时,那么就无法使用内置的format,需要开发者自己去设置

一些场景分析

Keywords

schme-form

FAQs

Package last updated on 28 Jul 2019

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

About

Packages

Stay in touch

Get open source security insights delivered straight into your inbox.

  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc

U.S. Patent No. 12,346,443 & 12,314,394. Other pending.