表单
FatForm 在 el-form 的基础之上进行了增强,配合原件,我们只需少量的配置就可以完成表单的开发。
以下是 FatForm 相关的套件:
1. 表单布局
FatForm 支持 3 种典型的布局:
查看代码
<template>
<div>
<div style="margin-bottom: 20px">
<el-radio-group v-model="layout">
<el-radio-button label="horizontal"></el-radio-button>
<el-radio-button label="vertical"></el-radio-button>
<el-radio-button label="inline"></el-radio-button>
</el-radio-group>
</div>
<FatForm :layout="layout" :submit="handleSubmit">
<FatFormItem label="用户名" prop="name" trim="blur"></FatFormItem>
<FatFormItem label="密码" prop="password" value-type="password"></FatFormItem>
</FatForm>
</div>
</template>
<script setup lang="tsx">
import { FatForm, FatFormItem } from '@wakeadmin/components';
import { ref } from 'vue';
const layout = ref<any>('horizontal');
const handleSubmit = async (value: any) => {
console.log(value);
};
</script>
1.1 分组
使用 FatFormGroup
可以对灵活地组合表单项, 让布局更加简单。
水平组合:
查看代码
<template>
<FatForm :enable-submitter="false">
<FatFormGroup>
<FatFormItem prop="name" label="名称"></FatFormItem>
<FatFormItem prop="password" label="密码" value-type="password"></FatFormItem>
<FatFormItem prop="remember" value-type="checkbox" :value-props="{ label: '记住密码' }"></FatFormItem>
</FatFormGroup>
<FatFormItem label="角色" prop="role" value-type="select"></FatFormItem>
</FatForm>
</template>
<script lang="tsx" setup>
import { FatForm, FatFormItem, FatFormGroup } from '@wakeadmin/components';
</script>
垂直组合:
查看代码
<template>
<FatForm :enable-submitter="false">
<FatFormGroup label="分组" vertical>
<FatFormItem prop="group[0]"></FatFormItem>
<FatFormItem prop="group[1]"></FatFormItem>
<FatFormItem prop="group[2]"></FatFormItem>
</FatFormGroup>
</FatForm>
</template>
<script lang="tsx" setup>
import { FatForm, FatFormItem, FatFormGroup } from '@wakeadmin/components';
</script>
混编:
查看代码
<template>
<FatForm :enable-submitter="false">
<FatFormGroup>
获取积分后, 第
<FatFormItem prop="name" value-type="integer" width="mini"></FatFormItem>
个 3 月 31 日 23:59:59 失效
</FatFormGroup>
</FatForm>
</template>
<script lang="tsx" setup>
import { FatForm, FatFormItem, FatFormGroup } from '@wakeadmin/components';
</script>
1.2 预定义宽度
我们预定义了一些表单项宽度,可以满足大多数表单场景,实现快捷开发的同时,保证 UI 的一致性:
mini
=104px 适用于短数字、短文本或选项。small
=216px 适用于较短字段录入、如姓名、电话、ID 等。medium
=328px 标准宽度,适用于大部分字段长度。large
=440px 适用于较长字段录入,如长网址、标签组、文件路径等。huge
=552px 适用于长文本录入,如长链接、描述、备注等,通常搭配自适应多行输入框或定高文本域使用。
示例:
查看代码
<template>
<FatForm>
<FatFormItem prop="mini0" label="短文本(mini)" width="mini"> </FatFormItem>
<FatFormItem
prop="mini1"
label="短数字(mini)"
width="mini"
value-type="integer"
:value-props="{ placeholder: '数字' }"
>
</FatFormItem>
<FatFormItem prop="small" label="较短文本(small)" width="small"></FatFormItem>
<FatFormItem prop="medium" label="标准文本(medium)" width="medium" message="适合大部分字段长度"></FatFormItem>
<FatFormItem
prop="large"
label="长字段(large)"
width="large"
value-type="url"
message="适用于较长字段录入,如长网址、标签组、文件路径等"
></FatFormItem>
<FatFormItem
prop="huge"
label="长文本输入(huge)"
width="huge"
value-type="textarea"
message="552px 适用于长文本录入,如长链接、描述、备注等,通常搭配自适应多行输入框或定高文本域使用"
></FatFormItem>
</FatForm>
</template>
<script lang="tsx" setup>
import { FatForm, FatFormItem } from '@wakeadmin/components';
</script>
1.3 网格布局
大部分场景我们推荐使用 FatFormGroup + width 来进行布局。 当然传统的网格布局我们依旧支持
查看代码
<template>
<FatForm>
<FatFormItem label="标题" prop="name" tooltip="最长 24 位"></FatFormItem>
<FatFormGroup>
<FatFormItem :col="{ md: 12, xl: 8 }" prop="company" label="姓名"></FatFormItem>
<FatFormItem :col="{ md: 12, xl: 8 }" prop="phone" label="电话"></FatFormItem>
<FatFormItem :col="{ md: 12, xl: 8 }" prop="email" label="邮箱"></FatFormItem>
</FatFormGroup>
<FatFormItem :col="24" prop="textarea" value-type="textarea" label="文本框"></FatFormItem>
<FatFormGroup>
<FatFormItem :col="12" prop="date" value-type="date" label="入职时间"></FatFormItem>
<FatFormItem :col="12" prop="dateRange" value-type="date-range" label="工作周期"></FatFormItem>
</FatFormGroup>
</FatForm>
</template>
<script lang="tsx" setup>
import { FatForm, FatFormItem, FatFormGroup } from '@wakeadmin/components';
</script>
FatFormGroup
在这里的作用就是充当 Row, 如果要进一步控制 row 的行为,可以通过 FatFormGroup
#row 属性进行配置。
FatFormGroup
、FatFormItem
都可以作为网格的单元格,通过 col
来配置单元格。
TIP
FatFormGroup
会自动检测子节点是否开启了网格,默认情况使用 FatSpace 来分组布局。
1.4 固定网格
某些场景,我们可能想要让所有的字段统一使用一个单元格配置,比如查询表单。这种情况可以使用 FatForm
的 col 属性来配置:
查看代码
<template>
<FatForm :col="{ xl: 6, lg: 8, sm: 12 }" label-width="100px">
<FatFormItem prop="a" label="名称"></FatFormItem>
<FatFormItem prop="b" label="姓名"></FatFormItem>
<FatFormItem prop="c" label="收货地址"></FatFormItem>
<FatFormItem prop="d" label="手机号码"></FatFormItem>
</FatForm>
</template>
<script lang="tsx" setup>
import { FatForm, FatFormItem } from '@wakeadmin/components';
</script>
1.5 提示信息
FatForm 内置了提示信息
查看代码
<template>
<FatForm :enable-submitter="false">
<FatFormItem prop="a" label="默认" message="默认提示信息,位于表单下方"></FatFormItem>
<FatFormItem prop="b" label="内联" inline-message message="内联提示信息"></FatFormItem>
<FatFormItem prop="c" label="悬浮信息" tooltip="这是悬浮提示信息"></FatFormItem>
</FatForm>
</template>
<script lang="tsx" setup>
import { FatForm, FatFormItem } from '@wakeadmin/components';
</script>
1.6 分类
复杂的表单会包含很多字段,适当分类用户体验会更加好:
查看代码
<template>
<FatForm :enable-submitter="false">
<FatFormSection title="基本信息">
<FatFormItem prop="name" label="名称" width="medium" :rules="{ required: true }"></FatFormItem>
<FatFormItem prop="age" label="年龄" width="huge"></FatFormItem>
</FatFormSection>
<FatFormSection title="详细信息">
<FatFormItem prop="id" label="身份证" width="large"></FatFormItem>
<FatFormItem prop="address" label="地址" width="large"></FatFormItem>
<FatFormItem prop="note" label="备注" width="huge" value-type="textarea"></FatFormItem>
</FatFormSection>
</FatForm>
</template>
<script lang="tsx" setup>
import { FatForm, FatFormItem, FatFormSection } from '@wakeadmin/components';
</script>
1.7 居中布局
居中布局在一些简单的表单场景也是比较常见的,居中可以让界面看起来更加美观
查看代码
<template>
<FatForm :enable-submitter="false" :style="{ maxWidth: '500px', margin: '0 auto' }">
<FatFormItem prop="id" label="身份证" width="large"></FatFormItem>
<FatFormItem prop="address" label="地址" width="large"></FatFormItem>
<FatFormItem prop="note" label="备注" width="huge" value-type="textarea"></FatFormItem>
</FatForm>
</template>
<script lang="tsx" setup>
import { FatForm, FatFormItem } from '@wakeadmin/components';
</script>
1.8 自定义提交按钮
FatForm 也支持自定义提交按钮,不过只是简单的文案修改,可以通过 props 进行修改
查看代码
<template>
<FatForm :style="{ maxWidth: '500px', margin: '0 auto' }">
<FatFormItem prop="id" label="身份证" width="large" required></FatFormItem>
<FatFormItem prop="address" label="地址" width="large"></FatFormItem>
<FatFormItem prop="note" label="备注" width="huge" value-type="textarea"></FatFormItem>
<template #submitter="scope">
<FatFormGroup label-width="auto">
<el-button type="primary" @click="scope.submit">自定义提交</el-button>
<el-button>自定义按钮</el-button>
</FatFormGroup>
</template>
</FatForm>
</template>
<script lang="tsx" setup>
import { FatForm, FatFormItem, FatFormGroup } from '@wakeadmin/components';
</script>
复用内置的提交按钮:
查看代码
<template>
<FatForm :style="{ maxWidth: '500px', margin: '0 auto' }">
<FatFormItem prop="id" label="身份证" width="large" required></FatFormItem>
<FatFormItem prop="address" label="地址" width="large"></FatFormItem>
<FatFormItem prop="note" label="备注" width="huge" value-type="textarea"></FatFormItem>
<template #submitter="scope">
<FatFormGroup label-width="auto">
<!-- vue template 不是直接渲染 VNode,可以使用 FatVNode 组件间接渲染 -->
<FatVNode :vnode="scope.renderButtons()" />
<el-button>自定义按钮</el-button>
</FatFormGroup>
</template>
</FatForm>
</template>
<script lang="tsx" setup>
import { FatForm, FatFormItem, FatFormGroup, FatVNode } from '@wakeadmin/components';
</script>
查看 defineFatForm 版本代码
import { defineFatForm } from '@wakeadmin/components';
import { ElButton } from 'element-plus';
export default defineFatForm(({ item, group, renderChild }) => {
return () => ({
style: { maxWidth: '500px', margin: '0 auto' },
children: [
item({ prop: 'id', label: '身份证', width: 'large', required: true }),
item({ prop: 'address', label: '地址', width: 'large' }),
item({ prop: 'note', label: '备注', width: 'huge', valueType: 'textarea' }),
],
renderSubmitter(form) {
return renderChild(
group({
labelWidth: 'auto',
children: [form.renderButtons(), <ElButton>自定义按钮</ElButton>],
})
);
},
});
});
2. 表单数据
FatForm 会在内部维护表单的数据,用户有三种方式来设置表单的初始值
:
- 通过
initialValue
- 通过
request
方法远程请求 - 通过
FatFormItem
的initialValue
配置
如果没配置初始值,FatForm 会自动初始化。
2.1 通过 initialValue 传入初始值
查看代码
<template>
<FatForm :initial-value="initialValue">
<FatFormItem label="账号名" prop="name"></FatFormItem>
<FatFormItem label="昵称" prop="nickName"></FatFormItem>
</FatForm>
</template>
<script lang="tsx" setup>
import { FatForm, FatFormItem } from '@wakeadmin/components';
const initialValue = {
name: 'ivan',
nickName: '狗蛋',
};
</script>
默认情况下, 在 FatForm 启动时,initialValue 会进行一次深拷贝,然后作为表单的初始化状态。
如果你想要将表单变更的状态回写到 initialValue,可以开启 syncToInitialValues
选项:
查看代码
<template>
<FatForm :initial-value="initialValue" sync-to-initial-values>
<FatFormItem label="账号名" prop="name"></FatFormItem>
<FatFormItem label="昵称" prop="nickName"></FatFormItem>
<FatFormGroup label="数据">
<pre><code>{{JSON.stringify(initialValue, null, 2)}}</code></pre>
</FatFormGroup>
</FatForm>
</template>
<script lang="tsx" setup>
import { FatForm, FatFormItem, FatFormGroup } from '@wakeadmin/components';
import { reactive } from 'vue';
const initialValue = reactive({
name: 'ivan',
nickName: '狗蛋',
});
</script>
在 FatFormItem
上也可以设置初始化值,这种方式会更加灵活,尤其是在 动态表单 的场景:
查看代码
<template>
<FatForm>
<FatFormItem label="账号名" prop="name" initial-value="ivan"></FatFormItem>
<FatFormItem label="昵称" prop="nickName" initial-value="狗蛋"></FatFormItem>
</FatForm>
</template>
<script lang="tsx" setup>
import { FatForm, FatFormItem } from '@wakeadmin/components';
</script>
2.2 通过 request 远程请求数据
很多场景我们是从远程服务器拉取数据来编辑的,这种情况可以使用 request 方法:
查看代码
<template>
<FatForm :request="request">
<FatFormItem label="账号名" prop="name"></FatFormItem>
<FatFormItem label="昵称" prop="nickName"></FatFormItem>
</FatForm>
</template>
<script lang="tsx" setup>
import { FatForm, FatFormItem } from '@wakeadmin/components';
const request = async () => {
return {
name: 'ivan',
nickName: '狗蛋',
};
};
</script>
从远程返回的数据未必符合要求。比如时间区间,后端通常会拆成两个字段,而我们的组件用一个字段。另外一种场景是数据格式的转换。
- 这两者都可以在 request 中处理。
- 如果是纯粹的数据转换,也可以通过 FatFormItem 的 convert 属性来处理
使用示例:
查看代码
<template>
<FatForm :request="request" layout="inline">
<FatFormItem label="时间区间" prop="dateRange" value-type="date-range"></FatFormItem>
<FatFormItem label="生日" prop="birthday" value-type="date" :convert="timestampToDate"></FatFormItem>
</FatForm>
</template>
<script lang="tsx" setup>
import { FatForm, FatFormItem } from '@wakeadmin/components';
// 模拟请求, 假设后端返回时间戳
const fetchData = () =>
Promise.resolve({
startDate: new Date('2012/12/12 12:12:12').getTime(),
endDate: new Date('2012/12/14 12:12:12').getTime(),
birthday: Date.now(),
});
const timestampToDate = (timestamp: number | undefined) => timestamp && new Date(timestamp);
// 复杂转换推荐在 request 中进行
const request = async () => {
const { startDate, endDate, ...other } = await fetchData();
return {
dateRange: [timestampToDate(startDate), timestampToDate(endDate)],
...other,
};
};
</script>
2.3 表单项
FatForm 并没有提供直接修改表单数据的手段,比如 el-form 官方使用 v-model
来修改状态:
<el-form :inline="true" :model="formInline" class="demo-form-inline">
<el-form-item label="审批人">
<el-input v-model="formInline.user" placeholder="审批人"></el-input>
</el-form-item>
<el-form-item label="活动区域">
<el-select v-model="formInline.region" placeholder="活动区域">
<el-option label="区域一" value="shanghai"></el-option>
<el-option label="区域二" value="beijing"></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit">查询</el-button>
</el-form-item>
</el-form>
而 FatForm 下统一使用 FatFormItem 的 prop
来定义字段的路径:
查看代码
<template>
<FatForm>
<FatFormItem label="审批人" prop="user" placeholder="审批人" width="small"></FatFormItem>
<FatFormItem
label="活动区域"
prop="region"
placeholder="活动区域"
width="small"
value-type="select"
:value-props="{
options: [
{ label: '区域一', value: 'shanghai' },
{ label: '区域二', value: 'beijing' },
],
}"
></FatFormItem>
</FatForm>
</template>
<script lang="tsx" setup>
import { FatForm, FatFormItem } from '@wakeadmin/components';
</script>
prop 是一个查询路径, 和 JavaScript 的对象成员语法一致, 格式示例:
a.b.c
a.b[0] # 数组
a.b[0].c # 数组
2.4 表单联动
复杂的表单绕不开表单之间的联动。 在 FatForm 中,我们推荐使用 FatFormConsumer
组件来实现联动:
查看代码
<template>
<FatForm :enable-submitter="false">
<FatFormItem label="签约客户名称" prop="user" width="medium"></FatFormItem>
<FatFormConsumer v-slot="scope">
<FatFormItem
prop="agree"
label-width="auto"
value-type="checkbox"
:disabled="!scope.values.user"
:value-props="{ label: `同意与 《${scope.values.user || '客户名称'}》签订合同` }"
></FatFormItem>
</FatFormConsumer>
</FatForm>
</template>
<script lang="tsx" setup>
import { FatForm, FatFormItem, FatFormConsumer } from '@wakeadmin/components';
</script>
TIP
如上面的代码所示,如果 FatFormItem 没有配置 label,如果想要和其他 FatFormItem 对齐,需要显式配置 labelWidth
为 auto
3. 表单提交
下面介绍 FatForm 表单提交的处理过程
数据提交的过程如上所示。
3.1 表单验证
表单验证的过程基本和 el-form 没多大差别。FatForm 增强了联动验证的支持。比如修改密码的场景:
查看代码
<template>
<FatForm>
<FatFormItem label="密码" prop="password" value-type="password" :rules="passwordRule"></FatFormItem>
<FatFormItem
label="确认密码"
prop="passwordConfirm"
value-type="password"
:rules="passwordConfirmRule"
dependencies="password"
></FatFormItem>
</FatForm>
</template>
<script lang="tsx" setup>
import { FatForm, FatFormItem, FatFormItemRules } from '@wakeadmin/components';
interface T {
password?: string;
passwordConfirm?: string;
}
const rule: (compareKey: keyof T) => FatFormItemRules<T> = compareKey => values =>
[
{ required: true },
{
validator(_rule: any, value, callback) {
if (value && values[compareKey] && value !== values[compareKey]) {
callback(new Error('密码不匹配'));
} else {
callback();
}
},
},
];
const passwordRule = rule('passwordConfirm');
const passwordConfirmRule = rule('password');
</script>
FatForm
,FatFormItem
的 rules 支持传入函数,可以获取表单值和表单实例。实现联动验证FatFormItem
的dependencies
属性可以用于设置依赖字段。当依赖的字段变动时,会触发当前字段重新验证
子表单验证
还有一种复杂的表单场景,即父子表单:
即某个字段底层也是一个 FatForm, 我们期望在触发验证或重置时也能带动这些子表单。FatForm 通过开启 hierarchyConnect
选项来支持这种关联。 默认开启。
开启后,父子 FatForm 会建立以下关联关系:
- 全局验证: 父 FatForm 在验证时,同时会触发子 FatForm 的验证
- 全局清理验证
3.2 表单数据转换
和上文 request 中的数据转换一样。如果输入端转换了,输出端的转换也是必然的过程。
对应的,复杂的数据转换可以在 submit 处理器中处理,简单的数据转换可以在 FatFormItem transform
中处理:
查看代码
<template>
<FatForm :submit="submit" layout="inline">
<FatFormItem
label="时间区间"
prop="dateRange"
value-type="date-range"
:value-props="{ valueFormat: 'x' }"
:transform="v => ({ startDate: v?.[0], endDate: v?.[1] })"
></FatFormItem>
<FatFormItem label="生日" prop="birthday" value-type="date" :value-props="{ valueFormat: 'x' }"></FatFormItem>
</FatForm>
</template>
<script lang="tsx" setup>
import { FatForm, FatFormItem } from '@wakeadmin/components';
// 复杂转换推荐在 submit 中进行
const submit = async (values: any) => {
console.log(values);
};
</script>
transform
的转换规则如下:
/**
* @param value 当前值
* @param values 当前所有表单的值
* @param prop 字段路径
*/
transform?: (value: any, values: Store, prop: string) => any
- 如果返回一个对象,key 为新属性的 path, 例如 {'a.b': 0, 'a.c': 2, 'a.d[0]': 3}, 同时原本的字段会被移除
- 如果返回非对象的值,将作为当前字段的值
假设:
prop 为 dataRange
transform 返回的是 {startTime、endTime}
最后的结果是 dataRange 会从 query 中移除,并且 startTime、endTime 会合并到 query 中
3.3 表单提交
接下来就是提交数据到远程了。数据经过验证和转换之后会传递给 submit 属性。如果数据保存成功,会触发 onFinish 事件:
<template>
<FatForm :submit="handleSubmit" @finish="handleFinish">
<!-- ... -->
</FatForm>
</template>
<script setup>
const handleSubmit = async values => {
// 后端数据请求
};
// 处理表单提交完成
const handleFinish = async values => {
// 成功保存
message.success('保存成功');
// or
history.back();
};
</script>
4. 动态表单
动态增删字段也是很常见的表单需求。
查看代码
<template>
<FatForm ref="formRef" :initial-value="initialValue">
<FatFormConsumer v-slot="form">
<FatFormGroup label="动态列表" vertical>
<FatFormGroup v-for="(item, index) of form.values.list" :key="item.key">
<FatFormItem :prop="`list[${index}].name`" placeholder="名称"></FatFormItem>
<FatFormItem :prop="`list[${index}].note`" placeholder="备注"></FatFormItem>
<el-button @click="handleRemove(item.key)">删除</el-button>
</FatFormGroup>
<el-button @click="handleAdd">新增</el-button>
</FatFormGroup>
</FatFormConsumer>
<FatFormItem label="显示隐藏字段" prop="visible" value-type="checkbox"></FatFormItem>
<FatFormConsumer v-slot="form">
<FatFormItem
v-if="form.values.visible"
label="我是隐藏字段"
prop="hidden"
initial-value="hidden"
width="medium"
:preserve="false"
></FatFormItem>
</FatFormConsumer>
<FatFormGroup label="数据">
<FatFormConsumer v-slot="form">
<pre><code>{{JSON.stringify(form.values, null, 2)}}</code></pre>
</FatFormConsumer>
</FatFormGroup>
</FatForm>
</template>
<script lang="tsx" setup>
import { FatForm, FatFormGroup, FatFormConsumer, FatFormItem, useFatFormRef } from '@wakeadmin/components';
interface S {
list: { name: string; note: string; key: number }[];
}
const formRef = useFatFormRef<S>();
let uid = 0;
const initialValue = {
list: [],
};
const handleAdd = () => {
formRef.value?.values.list.push({ name: '', note: '', key: uid++ });
};
const handleRemove = (key: number) => {
const idx = formRef.value?.values.list.findIndex(i => i.key === key);
if (idx != null && idx !== -1) {
formRef.value?.values.list.splice(idx, 1);
}
};
</script>
上面的代码展示了动态表单的简单处理过程。
另外还展示了条件展示字段, 通过 preserve
属性来控制,条件展示字段卸载后是否保留数据。
5. 预览模式
利用原件的 预览形态
和 编辑形态
, 我们现在可以做到一套代码就能满足 增改查
, 即编辑页面和详情预览。
查看代码
<template>
<div>
<div>
<el-switch v-model="previewMode" active-text="预览模式" inactive-text="编辑模式"></el-switch>
</div>
<FatForm :mode="previewMode ? 'preview' : 'editable'">
<FatFormItem prop="text" label="text" value-type="text" width="small" />
<FatFormItem prop="password" label="password" value-type="password" width="small" />
<FatFormItem prop="search" label="search" value-type="search" width="medium" />
<FatFormItem prop="textarea" label="textarea" value-type="textarea" width="huge" />
<FatFormItem prop="url" label="url" value-type="url" width="huge" />
<FatFormItem prop="date" label="date" value-type="date" width="medium" />
<FatFormItem prop="time" label="time" value-type="time" width="medium" />
<FatFormItem prop="dateTime" label="date-time" value-type="date-time" width="medium" />
<FatFormItem prop="dateRange" label="date-range" value-type="date-range" width="large" />
<FatFormItem prop="dateTimeRange" label="date-time-range" value-type="date-time-range" width="large" />
<FatFormItem prop="timeRange" label="time-range" value-type="time-range" width="large" />
<FatFormItem prop="switch" label="switch" value-type="switch" width="mini" />
<FatFormItem
prop="select"
label="select"
value-type="select"
width="small"
:value-props="{
options: [
{ label: '选项1', value: '1', color: 'primary' },
{ label: '选项2', value: '2', color: 'success' },
],
}"
/>
<FatFormItem
prop="multi-select"
label="multi-select"
value-type="multi-select"
width="small"
:value-props="{
options: [
{ label: '选项1', value: '1' },
{ label: '选项2', value: '2' },
],
separator: ' - ',
}"
/>
<FatFormGroup label="checkbox1">
<FatFormItem prop="checkbox1" value-type="checkbox" />
<span>同意 996 吗</span>
</FatFormGroup>
<FatFormItem prop="checkbox2" label-width="auto" value-type="checkbox" :value-props="{ label: '是否开启' }" />
<FatFormItem
prop="radio"
label="radio"
value-type="radio"
:value-props="{
options: [
{ label: '是', value: 1 },
{ label: '否', value: 0 },
],
}"
/>
<FatFormItem
prop="checkboxs"
label="checkboxs"
value-type="checkboxs"
:value-props="{
options: [
{ label: '选我', value: 1 },
{ label: '选我啊', value: 0 },
],
}"
/>
<FatFormItem prop="integer" label="integer" value-type="integer"></FatFormItem>
<FatFormItem prop="float" label="float" value-type="float"></FatFormItem>
<FatFormItem prop="currency" label="currency" value-type="currency"></FatFormItem>
<FatFormItem prop="rate" label="rate" value-type="rate"></FatFormItem>
<FatFormItem prop="slider" label="slider" value-type="slider" width="large"></FatFormItem>
<FatFormItem
prop="sliderVertical"
label="slider-vertical"
value-type="slider"
:value-props="{ vertical: true }"
></FatFormItem>
<FatFormItem prop="progress" label="progress" value-type="progress" :initial-value="50"></FatFormItem>
<FatFormItem
prop="images"
label="images"
value-type="images"
:value-props="{ sizeLimit: 1024 * 100, accept: ['.png', '.jpg'] }"
:rules="{ required: true }"
message="请上传文件,大小不超过 100 KB"
></FatFormItem>
</FatForm>
</div>
</template>
<script lang="tsx" setup>
import { ref } from 'vue';
import { FatForm, FatFormGroup, FatFormItem } from '@wakeadmin/components';
const previewMode = ref(false);
</script>
6. 自定义表单项
自定义表单项有两种方式:
- (推荐)自定义原件。
- 使用 FatFormConsumer 集成已有表单。
原件
是 @wakeadmin/components
的核心概念,我们优先推荐使用这种形式,将其构建成真正具备复用能力的组件。 详见自定义原件。
使用 FatFormConsumer 也可以使用将外部表单组件集成到 FatForm
的体系下:
查看代码
<template>
<FatForm :enable-submitter="false">
<FatFormItem label="姓名" prop="name" width="medium"></FatFormItem>
<FatFormConsumer v-slot="scope">
<el-form-item label="年龄">
<el-input-number
:model-value="scope.getFieldValue('age')"
@update:model-value="scope.setFieldValue('age', $event)"
/>
</el-form-item>
</FatFormConsumer>
<FatFormConsumer v-slot="scope">
<el-form-item label="JSON">
{{ JSON.stringify(scope.values, null, 2) }}
</el-form-item>
</FatFormConsumer>
</FatForm>
</template>
<script lang="tsx" setup>
import { FatForm, FatFormItem, FatFormConsumer } from '@wakeadmin/components';
</script>
7. 原件值映射(1.8+)
在 1.8 版本之前,表单项的数据转换只能通过 convert
和 transform
props 来实现, 而这两个方法的执行时机分别是在数据请求之后和表单提交之前。无法应付以下场景:
- 将日期字符串双向转换为 Date
- 将逗号分割的字符串转换为 数组
- 将 JSON 字符串还原
- 将字符串转换为数字
- 等等
为了应付这些场景,我们在 1.8 版本为 FatFormItem
引入了 valueMap 属性,使用方法如下:
查看代码
import { defineFatForm } from '@wakeadmin/components';
export default defineFatForm<{ json?: string }>(({ item, consumer }) => {
return () => ({
children: [
item({
label: 'JSON',
valueType: 'multi-select',
prop: 'json',
valueProps: {
options: [
{ label: '1', value: 1 },
{ label: '2', value: 2 },
],
},
valueMap: {
in: value => {
if (!value) {
return [];
}
try {
return JSON.parse(value as string);
} catch (e) {
return [];
}
},
out: value => {
if (!value) {
return '';
}
return JSON.stringify(value);
},
},
}),
consumer(scope => {
return <pre>{JSON.stringify(scope.values, null, 2)}</pre>;
}),
],
});
});
@wakeadmin/components 也内置了一些常见的 valueMap 供直接导入,例如:
- numberToString: 将原件的 number 类型转换为 string 类型
- toJSONArrayString: 将原件的数组转换为 JSON 字符串, 默认值为 []
- toJSONObjectString: 将原件的对象转换为 JSON 字符串, 默认值为 {}
- toCommaSplitArray: 将原件的数组转换为逗号分割的字符串, 默认值为 []
- toCommaSplitNumberArray: 将原件的数字数组转换为逗号分割的字符串, 默认值为 []