|
|
||
|---|---|---|
| .. | ||
| README.md | ||
| form-config.ts | ||
| form-item.tsx | ||
| form-modal.tsx | ||
| form-node.tsx | ||
| form-rules.ts | ||
| form.tsx | ||
| index.ts | ||
| use-form-modal.tsx | ||
| use-form.tsx | ||
| util.ts | ||
README.md
介绍
基于Arco-Design组件封装的表单,旨在通过较少的配置提升开发效率,将一些通过的状态管理内置,使得开发者只需关注核心内容即可快速开发通用型表单。
本表单适用于通用型表单,对于自定义要求较高的需求,可能不太适合。
功能
- 配置化编写代码,保证UI一致性,提供开发效率。
- 提供typesciprt类型提示
- 表单项和校验规则之间可联动、可动态显示/隐藏
- 内置常用校验规则,开箱即用
- 支持组件参数透传,让每个组件都能自定义。
基本功能
基本用法:
<template>
<Form v-bind="form" />
</template>
<script setup lang="ts">
import { Form, useForm } from '@/components'
const form = useForm({
model: {
id: undefined
},
items: [
{
field: 'username',
label: '用户名称',
type: 'input'
}
],
submit: async ({ model, items }) => {
await new Promise(res => setTimeout(res, 2000));
return { message: '操作成功!' }
},
formProps: {},
})
</script>
以上, 只有四个参数,只需定义关注的内容,剩下的内容如内部状态等, 由表单管理。
| 参数 | 说明 | 类型 |
|---|---|---|
| model | 表单数据(可选),默认从items每一项的field和initialValue生成,如果存在同名属性,将与其合并。 |
Record<string, any> |
| items | 表单项,具体用法看下文。 | FormItem[] |
| submit | 提交表单的函数,可为同步/异步函数。当有返回值且返回值为包含message的对象时,将弹出成功提示。 |
({ model, items }) => Promise<any> |
| formProps | 传递给AForm组件的参数(可选),具体可参考Arco-Design的Form组件,部分参数不可用,如model等。 |
FormInstance['$props'] |
表单数据
model表示当前表单的数据,可为空。当使用useForm时,将从items中每一项的field和initialValue生成。如果model中的属性与field值同名,且initialValue值不为空,则原model中的同名属性值将被覆盖。
对于日期范围框、级联选择器等值为数组的组件,提供有一份便捷的语法,请看如下示例:
const form = useForm({
items: [
{
field: `[startDate, endDate]`,
label: '日期范围',
type: 'dateRange',
},
{
field: '[provice: number, city: number, town: number]',
label: '省市区',
type: 'cascader',
options: []
}
]
})
以上,field 使用的是类似Typescript元组的写法,类型目前支持 number 和 boolean,在提交时将得到如下数据:
{
startDate: '2023',
endDate: '2024',
province: 1,
city: 2,
town: 3
}
表单项
用法示例:
const form = useForm({
items: [
{
field: 'username',
initialValue: 'apptify',
label: '用户名称',
type: 'input',
itemProps: {},
nodeProps: {},
visible: ({ model, item, items }) => true,
disable: ({ model, item, items }) => true,
required: true,
rules: ['email'],
options: ({ model }) => api.xx(model.id)
component: ({ model, item, items }) => <div> </div>,
help: string |
}
]
})
用法说明:
| 参数 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| field | 字段名,将合并合并到model中,默认值为undefined,可通过initalValue指定初始值 |
string | - |
| initialValue | 初始值, 作为默认初始值以及通过formRef.reset重置表单数据时的值 |
any | undefined |
| label | 标签名,可为字符串或函数, 作用同AFormItem的label参数 |
string | ({ model,item }) => JSX.Element | - |
| type | 输入控件的类型,具体可参考下文 | NodeType | 'input' |
| visible | 动态控制该表单项是否显示 | boolean | ({ model,item }) => boolean | - |
| disable | 动态控制该表单项是否禁止,作用同FormItem的disabled属性 |
boolean | ({ model, item }) => boolean | - |
| required | 是否必填,作用同AFormItem的required属性 |
boolean | - |
| rules | 校验规则,内置常用规则,并支持动态生效,详见下文 | RuleType[] | - |
| options | 作用域select等多选项组件,支持动态获取 |
(Option[]) | ({ model, item }) => Option[] | - |
| itemProps | 传递给AFormItem组件的参数,部分参数不可用,如上面的field等参数 |
FormItemInstance['$props'] | - |
| nodeProps | 传递给type属性对应组件的参数,如当type为input时, nodeProps类型为Input组件的props。 |
NodeProps | - |
控件类型
表单项的type指定表单控件的类型,当输入具体的值时,nodeProps会提供对应的参数类型提示。内置有常见的组件,且带有默认的参数,具体默认参数可在src/components/form/form-node.tsx中查看:
| 类型 | 说明 |
|---|---|
| input | 同 Input 组件 |
| number | 同 InputNumber 组件 |
| password | 同 InputPassword 组件 |
| select | 同 Select 组件 |
| time | 同 TimePicker 组件 |
| date | 同 DatePicker 组件 |
| dateRange | 同 RangePicker 组件 |
| textarea | 同 Textarea 组件 |
| cascader | 同 Cascader 组件 |
| checkbox | 同 Checkbox 组件 |
| radio | 同 Radio 组件 |
| slider | 同 Slider 组件 |
| submit | 提交表单按钮,应只有一个。 |
| custom | 自定义组件,通过表单项的component属性定义,需返回一个JSX元素。 |
对于select、checkbox、radio和cascader类型,其options参数不通过nodeProps传递,而是写在表单项的options属性。该属性支持数组和函数类型,当为数组类型时将直接传递给控件,当为函数时可动态请求,返回值需为数组类型。
以上描述,示例如下:
const form = useForm({
items: [
{
field: 'gender',
label: '性别',
type: 'select',
options: [
{
label: '男',
value: 1,
},
{
label: '女',
value: 2,
}
]
},
{
field: 'departmentId',
label: '部门',
type: 'cascader',
options: async ({ model, item }) => {
const res = await api.getDepartments(model.xx);
return res.data;
}
}
]
})
表单校验
跟表单校验相关的属性有2个,required(必填)和rules属性,其中rules内置常见的校验规则,参考如下:
| 校验规则 | 说明 |
|---|---|
| string | 格式为字符串 |
| number | 格式为数字 |
| passwod | 格式为密码类型,即至少包含大写字母、小写字母、数字和特殊字符。 |
| required | 该项必填 |
| 格式为邮箱类型,例如: xx@abc.com | |
| url | 格式为URL类型, 例如: https://abc.com |
| ip | 格式为IP类型, 例如: 101.10.10.302 |
| phone | 格式为11位手机号,例如: 15912345678 |
| idcard | 格式为18位身份证号,例如: 12345619991205131x |
| alphabet | 格式为26字母,例如:apptify |
当以上规则不满足需求时,可通过对象自定义校验规则,具体语法可参考AFormItem的 FieldRule 文档。在其基础上,可添加一个disable函数,用于动态禁止/允许当前校验规则。
用法示例:
const form = useForm({
items: [
{
required: true,
rules: [
'email',
{
match: /\d{2,3}/,
message: '请输入2~3位数字',
disable: ({ model, item, items }) => !model.username
}
],
}
]
})
提交表单
submit为提交表单的函数,通常返回一个promise,当该函数抛出异常,则默认为提交失败。该函数有一个可选的返回值,如果返回值为包含message的对象时,将弹出一个包含message值的成功提示。
示例如下:
const form = useForm({
submit: async ({ model, items }) => {
const res = await api.xx(model);
return { message: res.msg }
}
})
常见问题
- Q:为什么不是模板形式?
- A:状态驱动,配置式更易于描述逻辑,模板介入和引入的组件比较多,且对于做typescript类型提示不是很方便。
- Q:为什么不是JSON形式?
- A:对于自定义组件支持、联动等不是非常友好,尽管可以通过解析字符串执行等方式实现,对typescript提示不是很友好。
最后
尽管看起来是低代码,但其实我更倾向于是业务组件。