表单组件 - SForm
通过 Groups 配置渲染表单内容,当然也支持卡槽自定义组件。 (目前 Groups 已支持的表单组件如下)
ARate、
ASlider、
ASwitch、
ASelect、ATreeSelect、
ACascader、AAutoComplete、
ARadioGroup、ACheckboxGroup、
ADatePicker、AYearPicker、AMonthPicker、
AQuarterPicker、AWeekPicker、ATimePicker、ARangePicker、
AInput、AInputSearch、AInputNumber、AInputPassword、AInputTextarea
演示
基本用法
基本用法
支持通过 Props.groups
配置,渲染相应的表单组件
通过使用 formGroupsDefiner
提供 Typescript 提示和校验
复制代码
显示代码
vue
<template>
<SForm
v-model="model"
:layout="layout"
:labelCol="labelCol"
:disabled="disabled"
:readonly="readonly"
:spinning="spinning"
:groups="groups"
:grid="grid"
/>
</template>
<script setup lang="ts">
const disabled = ref(false)
const readonly = ref(false)
const spinning = ref(false)
// 注: 定义 Props 外的 Attrs,将作用在 SForm 组件中 AForm 组件上
const labelCol = { style: { width: '65px' } }
const layout = ref('horizontal')
// 定义 Groups
const groups = formGroupsDefiner([
{
type: 'AInput',
slot: '',
field: 'bInput',
label: '输入框',
props: {
placeholder: '请输入文本内容',
},
},
{
type: 'ASelect',
slot: '',
field: 'bSelect',
label: '下拉框',
props: {
placeholder: '请选择',
options: [
{
value: 'jack',
label: 'Jack',
},
{
value: 'lucy',
label: 'Lucy',
},
],
},
},
{
type: 'ADatePicker',
slot: '',
field: 'bDatePicker',
label: '年月日',
props: {
format: 'YYYY/MM/DD HH:mm',
valueFormat: 'YYYY-M-D H:m',
showTime: true,
},
},
{
type: 'ASlider',
slot: '',
field: 'bSlider',
label: '滑条',
},
{
type: 'ASwitch',
slot: '',
field: 'bSwitch',
label: '开关',
props: {
checkedValue: 'Y',
unCheckedValue: 'N',
checkedChildren: '开',
unCheckedChildren: '关',
},
},
])
// 定义 Grid
const grid = formGridDefiner({
gutter: 30,
xs: 24,
sm: 12,
md: 8,
})
// 定义 Model, 可以事先不在 model 声明字段
const model: Ref<any> = ref({
bInput: '这是一个输入框',
bSelect: 'jack',
bDatePicker: '2024-6-8 8:30',
bSlider: 35,
bSwitch: 'Y',
})
</script>
表单分组
表单分组
在 Props.groups
配置渲染表单组件时,我们可以通过 AGroup
以及 ARow
来定制适配不同的表单布局
复制代码
显示代码
vue
<template>
<div class="margin-container">
<SForm
v-model="model"
:labelCol="labelCol"
:disabled="disabled"
:readonly="readonly"
:spinning="spinning"
:groups="groups"
:grid="grid"
/>
</div>
</template>
<script setup lang="ts">
const disabled = ref(false)
const readonly = ref(false)
const spinning = ref(false)
const labelCol = { style: { width: '68px' } }
const groups = formGroupsDefiner([
// 第一个 AGroup
{
type: 'AGroup',
slot: '',
field: 'AGroup1',
label: '输入选择框', // 当 slot 和 label 都为空时,则不渲染 GroupHeader,
border: true, // 设置 GroupHeader border-bottom
},
{
type: 'AInput',
slot: '',
field: 'input',
label: '输入框',
props: {
placeholder: '请输入文本内容',
},
},
{
type: 'AInputPassword',
slot: '',
field: 'password',
label: '密码框',
props: {
rows: 1,
autoSize: true,
placeholder: '请输入密码',
},
},
{
type: 'AInputNumber',
slot: '',
field: 'number',
label: '数字框',
props: {
placeholder: '请输入数字',
},
},
{
type: 'ACascader',
slot: '',
field: 'cascader',
label: '级联',
props: {
placeholder: '请选择',
options: [
{
value: 'ZheJiang',
label: 'ZheJiang',
children: [
{
value: 'HangZhou',
label: 'HangZhou',
},
{
value: 'Ningbo',
label: 'Ningbo',
},
],
},
],
},
},
{
type: 'ASelect',
slot: '',
field: 'select',
label: '下拉框',
props: {
allowClear: true,
placeholder: '请选择',
options: [
{
value: 'jack',
label: 'Jack',
},
{
value: 'lucy',
label: 'Lucy',
},
],
},
},
{
type: 'ATreeSelect',
slot: '',
field: 'treeSelect',
label: '树选择',
props: {
allowClear: true,
showSearch: true,
treeDefaultExpandAll: true,
dropdownMatchSelectWidth: true,
treeNodeFilterProp: 'label',
placeholder: '请选择',
dropdownStyle: {
maxHeight: '300px',
},
treeData: [
{
label: 'A',
value: 'a',
children: [
{
label: 'A-1',
value: 'a-1',
},
{
label: 'A-2',
value: 'a-2',
},
],
},
{
label: 'B',
value: 'b',
children: [
{
label: 'B-1',
value: 'b-1',
},
{
label: 'B-2',
value: 'b-2',
},
],
},
],
},
},
// 第二个 AGroup
{
type: 'AGroup',
slot: '',
field: 'AGroup-2',
label: '日期选择框',
border: true,
grid: {},
},
{
type: 'AYearPicker',
slot: '',
field: 'yearPicker',
label: '选择年',
props: {
format: 'YYYY年',
},
},
{
type: 'AMonthPicker',
slot: '',
field: 'monthPicker',
label: '年月',
props: {
format: 'YYYY年MM月',
},
},
{
type: 'ADatePicker',
slot: '',
field: 'datePicker',
label: '年月日',
props: {
format: 'YYYY/MM/DD HH:mm',
valueFormat: 'YYYY-M-D H:m',
showTime: true,
},
},
{
type: 'AWeekPicker',
slot: '',
field: 'weekPicker',
label: '第几周',
props: {
format: 'YYYY年 ww周',
},
},
{
type: 'AQuarterPicker',
slot: '',
field: 'quarterPicker',
label: '季度',
props: {
format: 'YYYY年 Q季度',
},
},
{
type: 'ATimePicker',
slot: '',
field: 'timePicker',
label: '时间',
props: {
format: 'a h:mm',
valueFormat: 'HH:mm',
},
},
{
type: 'ARangePicker',
slot: '',
field: 'rangePicker',
label: '日期组',
props: {
format: 'YYYY年MM月DD日',
},
grid: {
md: 12,
},
},
// 第三个 AGroup
{
type: 'AGroup',
slot: '',
field: 'AGroup3',
label: '其他组件',
border: true,
grid: {
md: 6, // 覆盖 Form grid (md:8)
},
},
{
type: 'ASlider',
slot: '',
field: 'slider',
label: '滑条',
grid: {
md: 10, // 覆盖 AGroup grid (md:6)
},
},
{
type: 'ASwitch',
slot: '',
field: 'switch',
label: '开关',
props: {
checkedValue: 'Y',
unCheckedValue: 'N',
checkedChildren: '开',
unCheckedChildren: '关',
},
},
{
type: 'ARow',
grid: {
md: 12,
},
},
{
type: 'ACheckboxGroup',
slot: '',
field: 'checkbox',
label: '多选',
props: {
options: [
{ label: 'Apple', value: 'apple' },
{ label: 'Pear', value: 'pear' },
{ label: 'Orange', value: 'orange' },
],
},
},
{
type: 'ARow',
grid: {
md: 12,
},
},
{
type: 'ARadioGroup',
slot: '',
field: 'radio',
label: '单选',
props: {
options: [
{ label: 'Apple', value: 'apple' },
{ label: 'Pear', value: 'pear' },
{ label: 'Orange', value: 'orange' },
],
},
},
// 第四个 AGroup
{
type: 'AGroup',
slot: '',
field: 'AGroup4',
label: '表单实时数据',
border: true,
},
{
type: 'AInputTextarea',
slot: '',
field: 'textarea',
label: '',
props: {
readonly: true,
autoSize: true,
bordered: false,
placeholder: '请输入文本内容',
},
grid: {
md: 16,
},
},
])
const grid = formGridDefiner({
gutter: 12,
xs: 24,
sm: 12,
md: 8,
})
const model: Ref<any> = ref({
input: '这是一个输入框',
password: '12345678',
number: undefined,
cascader: ['ZheJiang', 'NingBo'],
treeSelect: 'a-1',
yearPicker: '2024',
monthPicker: '2024-06',
datePicker: '2024-6-8 8:30',
weekPicker: '2024-27',
quarterPicker: '2024-3',
timePicker: '09:35',
rangePicker: ['2024-05-15', '2024-09-25'],
slider: 35,
switch: 'Y',
checkbox: ['apple', 'pear'],
radio: 'pear',
})
watchEffect(() => {
const prints = []
const models = {
...model.value,
textarea: undefined,
}
for (const [key, value] of Object.entries(models)) {
if (key !== 'textarea') {
const stringer = (value: any) => typeof value === 'number' || typeof value === 'undefined' ? value : '"' + value + '"'
const arrayer = (value: any[]) => '[' + value.map(v => '"' + v + '"').join(', ') + ']'
const valuer = Array.isArray(value) ? arrayer(value) : stringer(value)
prints.push(` ${key}: ${valuer},`)
}
}
model.value.textarea = `{\n${prints.join('\n')}\n}\n---------- model.value ----------`
})
</script>
<style lang="less" scoped>
.margin-container {
margin-top: -25px;
margin-bottom: -40px;
}
</style>
表单校验
表单校验
我们通过 Props.rules
统一配置表单各组件的校验规则,也可以在表单各组件的 rule
选项中进行配置
复制代码
显示代码
vue
<template>
<div class="margin-container">
<ASpace
:size="15"
:wrap="true"
style="margin: 0"
direction="vertical"
>
<ASpace :size="15">
<AButton @click="form?.validateFields()">
表单校验
</AButton>
<AButton @click="form?.resetFields()">
表单重置
</AButton>
</ASpace>
<SForm
ref="form"
v-model="model"
:labelCol="labelCol"
:disabled="disabled"
:readonly="readonly"
:spinning="spinning"
:groups="groups"
:rules="rules"
:grid="grid"
/>
</ASpace>
</div>
</template>
<script setup lang="ts">
const disabled = ref(false)
const readonly = ref(false)
const spinning = ref(false)
const form = ref(null as InstanceType<SForm> | null)
const labelCol = { style: { width: '68px' } }
const groups = formGroupsDefiner([
{
type: 'AGroup',
slot: '',
field: 'AGroup1',
label: '输入选择框',
border: true,
},
{
type: 'AInput',
slot: '',
field: 'cInput',
label: '输入框',
props: {
allowClear: true,
placeholder: '请输入文本内容',
},
},
{
type: 'AInputPassword',
slot: '',
field: 'cPassword',
label: '密码框',
props: {
rows: 1,
autoSize: true,
allowClear: true,
placeholder: '请输入密码',
},
},
{
type: 'AInputNumber',
slot: '',
field: 'cNumber',
label: '数字框',
props: {
placeholder: '请输入数字',
},
rules: [{ required: true, message: '数字不可为空' }], // 覆盖 props.rules
},
{
type: 'ACascader',
slot: '',
field: 'cCascader',
label: '级联',
props: {
allowClear: true,
placeholder: '请选择',
options: [
{
value: 'ZheJiang',
label: 'ZheJiang',
children: [
{
value: 'HangZhou',
label: 'HangZhou',
},
{
value: 'Ningbo',
label: 'Ningbo',
},
],
},
],
},
},
{
type: 'ASelect',
slot: '',
field: 'cSelect',
label: '下拉框',
props: {
allowClear: true,
placeholder: '请选择',
options: [
{
value: 'jack',
label: 'Jack',
},
{
value: 'lucy',
label: 'Lucy',
},
],
},
rules: [{ required: true, message: '请选择一个成员' }], // 覆盖 props.rules
},
{
type: 'ATreeSelect',
slot: '',
field: 'cTreeSelect',
label: '树选择',
props: {
allowClear: true,
showSearch: true,
treeDefaultExpandAll: true,
dropdownMatchSelectWidth: true,
treeNodeFilterProp: 'label',
placeholder: '请选择',
dropdownStyle: {
maxHeight: '300px',
},
treeData: [
{
label: 'A',
value: 'a',
children: [
{
label: 'A-1',
value: 'a-1',
},
{
label: 'A-2',
value: 'a-2',
},
],
},
{
label: 'B',
value: 'b',
children: [
{
label: 'B-1',
value: 'b-1',
},
{
label: 'B-2',
value: 'b-2',
},
],
},
],
},
},
{
type: 'AGroup',
slot: '',
field: 'AGroup-2',
label: '日期选择框',
border: true,
grid: {},
},
{
type: 'AYearPicker',
slot: '',
field: 'cYearPicker',
label: '选择年',
props: {
allowClear: true,
format: 'YYYY年',
},
rules: [{ required: true, message: '请选择年份' }],
},
{
type: 'AMonthPicker',
slot: '',
field: 'cMonthPicker',
label: '年月',
props: {
allowClear: true,
format: 'YYYY年MM月',
},
},
{
type: 'ADatePicker',
slot: '',
field: 'cDatePicker',
label: '年月日',
props: {
allowClear: true,
format: 'YYYY/MM/DD',
valueFormat: 'YYYY-MM-DD',
},
},
{
type: 'AQuarterPicker',
slot: '',
field: 'cQuarterPicker',
label: '季度',
props: {
allowClear: true,
format: 'YYYY年 Q季度',
},
},
{
type: 'ATimePicker',
slot: '',
field: 'cTimePicker',
label: '时间',
props: {
allowClear: true,
format: 'a h:mm',
valueFormat: 'HH:mm',
},
},
])
const rules = formRulesDefiner({
cInput: [{ required: true, message: '请输入内容' }],
cNumber: [{ required: true, message: '请输入数字' }], // 被覆盖
cCascader: [{ required: true, message: '请选择省市' }],
cSelect: [{ required: true, message: '请选择' }], // 被覆盖
cTreeSelect: [{ required: true, message: '请选择' }],
cMonthPicker: [{ required: true, message: '请选择年月' }],
cDatePicker: [{ required: true, message: '请选择年月日' }],
cQuarterPicker: [{ required: true, message: '请选择季度' }],
cTimePicker: [{ required: true, message: '请选择时间' }],
cPassword: formValidator.password({
message: '请输入用户密码',
validator: '用户密码过短',
pattern: /.{8,}/,
required: true,
}),
})
const grid = formGridDefiner({
gutter: 12,
xs: 24,
sm: 12,
md: 8,
})
const model: Ref<any> = ref({
cInput: '这是一个输入框',
cPassword: '123456',
cCascader: ['ZheJiang', 'NingBo'],
cYearPicker: '2024',
cMonthPicker: '2024-06',
cNumber: undefined,
})
</script>
<style lang="less" scoped>
.margin-container {
margin-bottom: -40px;
}
</style>
自定义分组
自定义分组
我们可以通过 AGroup.slot
自定义表单分组 Header, 也可以配置各分组下组件可用状态 (禁用/只读)
复制代码
显示代码
vue
<template>
<div class="margin-container">
<SForm
v-model="model"
:labelCol="labelCol"
:disabled="disabled"
:readonly="readonly"
:spinning="spinning"
:groups="groups"
:grid="grid"
>
<template #s-header-group-1="{ className, group }">
<div
:class="className"
style="display: flex; align-items: center;"
>
<div style="flex: 1 1 auto">
{{ group.label }} {{ group.disabled ? '(已禁用)' : '(正常)' }}
</div>
<ASwitch
v-model:checked="group.disabled"
style="margin-right: 10px"
unCheckedChildren="正常"
checkedChildren="禁用"
/>
</div>
</template>
<template #s-header-group-2="{ className, group }">
<div
:class="className"
style="display: flex; align-items: center;"
>
<div style="flex: 1 1 auto">
{{ group.label }} {{ group.readonly ? '(只读)' : '(正常)' }}
</div>
<ASwitch
v-model:checked="group.readonly"
style="margin-right: 10px"
unCheckedChildren="正常"
checkedChildren="只读"
/>
</div>
</template>
</SForm>
</div>
</template>
<script setup lang="ts">
const disabled = ref(false)
const readonly = ref(false)
const spinning = ref(false)
const labelCol = { style: { width: '68px' } }
const groups = formGroupsDefiner([
{
type: 'AGroup',
slot: 'group-1', // s-header-[slotName]
field: 'AGroup1',
label: '输入选择框',
disabled: ref(true),
border: true,
},
{
type: 'AInput',
slot: '',
field: 'gInput',
label: '输入框',
props: {
allowClear: true,
placeholder: '请输入文本内容',
},
},
{
type: 'AInputPassword',
slot: '',
field: 'gPassword',
label: '密码框',
props: {
rows: 1,
autoSize: true,
allowClear: true,
placeholder: '请输入密码',
},
},
{
type: 'AInputNumber',
slot: '',
field: 'gNumber',
label: '数字框',
props: {
placeholder: '请输入数字',
},
},
{
type: 'ACascader',
slot: '',
field: 'gCascader',
label: '级联',
props: {
allowClear: true,
placeholder: '请选择',
options: [
{
value: 'ZheJiang',
label: 'ZheJiang',
children: [
{
value: 'HangZhou',
label: 'HangZhou',
},
{
value: 'Ningbo',
label: 'Ningbo',
},
],
},
],
},
},
{
type: 'ASelect',
slot: '',
field: 'gSelect',
label: '下拉框',
props: {
allowClear: true,
placeholder: '请选择',
options: [
{
value: 'jack',
label: 'Jack',
},
{
value: 'lucy',
label: 'Lucy',
},
],
},
},
{
type: 'ATreeSelect',
slot: '',
field: 'gTreeSelect',
label: '树选择',
props: {
allowClear: true,
showSearch: true,
treeDefaultExpandAll: true,
dropdownMatchSelectWidth: true,
treeNodeFilterProp: 'label',
placeholder: '请选择',
dropdownStyle: {
maxHeight: '300px',
},
treeData: [
{
label: 'A',
value: 'a',
children: [
{
label: 'A-1',
value: 'a-1',
},
{
label: 'A-2',
value: 'a-2',
},
],
},
{
label: 'B',
value: 'b',
children: [
{
label: 'B-1',
value: 'b-1',
},
{
label: 'B-2',
value: 'b-2',
},
],
},
],
},
},
{
type: 'AGroup',
slot: 's-header-group-2', // s-header-*
field: 'AGroup-2',
label: '日期选择框',
readonly: ref(true),
border: true,
},
{
type: 'AYearPicker',
slot: '',
field: 'gYearPicker',
label: '选择年',
props: {
allowClear: true,
format: 'YYYY年',
},
},
{
type: 'AMonthPicker',
slot: '',
field: 'gMonthPicker',
label: '年月',
props: {
allowClear: true,
format: 'YYYY年MM月',
},
},
{
type: 'ADatePicker',
slot: '',
field: 'gDatePicker',
label: '年月日',
props: {
allowClear: true,
format: 'YYYY/MM/DD',
valueFormat: 'YYYY-MM-DD',
},
},
{
type: 'AQuarterPicker',
slot: '',
field: 'gQuarterPicker',
label: '季度',
props: {
allowClear: true,
format: 'YYYY年 Q季度',
},
},
{
type: 'ATimePicker',
slot: '',
field: 'gTimePicker',
label: '时间',
props: {
allowClear: true,
format: 'a h:mm',
valueFormat: 'HH:mm',
},
},
])
const grid = formGridDefiner({
gutter: 12,
xs: 24,
sm: 12,
md: 8,
})
const model: Ref<any> = ref({
gInput: '这是一个输入框',
gPassword: '123456',
gCascader: ['ZheJiang', 'NingBo'],
gYearPicker: '2024',
gMonthPicker: '2024-06',
gNumber: undefined,
})
</script>
<style lang="less" scoped>
.margin-container {
margin-top: -25px;
margin-bottom: -40px;
}
</style>
自定义组件
自定义组件
除了自定义表单分组,我们也可以通过 [Component].slot
自定义表单各组件。例:
- AInput 输入框
- ASelect 下拉框
- ADatePicker 年月日
复制代码
显示代码
vue
<template>
<div class="margin-container">
<SForm
v-model="model"
:labelCol="labelCol"
:disabled="disabled"
:readonly="readonly"
:spinning="spinning"
:groups="groups"
:rules="rules"
:grid="grid"
>
<template #s-component-input="{ source, field, attrs }">
<AInput
v-model:value="source[field]"
v-bind="attrs"
>
<template #addonAfter>
<SettingOutlined />
</template>
</AInput>
</template>
<template #s-component-select="{ source, field, attrs }">
<SIconSelect
v-model:value="source[field]"
v-bind="attrs"
mode="tags"
/>
</template>
<template #s-component-date="{ source, field, attrs }">
<ADatePicker
v-model:value="source[field]"
v-bind="attrs"
:open="open"
@change="open = false"
@focus="open = true"
@blur="open = false"
>
<template #suffixIcon>
<BellOutlined />
</template>
</ADatePicker>
</template>
</SForm>
</div>
</template>
<script setup lang="ts">
const disabled = ref(false)
const readonly = ref(false)
const spinning = ref(false)
// 年月日组件 弹窗
const open = ref(false)
const labelCol = { style: { width: '68px' } }
const groups = formGroupsDefiner([
// 第一个 AGroup
{
type: 'AGroup',
slot: '',
field: 'AGroup1',
label: '输入选择框',
border: true,
},
{
type: 'AInput',
slot: 'input', // s-component-[slotname]
field: 'sInput',
label: '输入框',
props: {
allowClear: true,
placeholder: '请输入文本内容',
},
},
{
type: 'AInputPassword',
slot: '',
field: 'sPassword',
label: '密码框',
props: {
rows: 1,
autoSize: true,
allowClear: true,
placeholder: '请输入密码',
},
},
{
type: 'AInputNumber',
slot: '',
field: 'sNumber',
label: '数字框',
props: {
placeholder: '请输入数字',
},
},
{
type: 'ACascader',
slot: '',
field: 'sCascader',
label: '级联',
props: {
allowClear: true,
placeholder: '请选择',
options: [
{
value: 'ZheJiang',
label: 'ZheJiang',
children: [
{
value: 'HangZhou',
label: 'HangZhou',
},
{
value: 'Ningbo',
label: 'Ningbo',
},
],
},
],
},
},
{
type: 'ASelect',
slot: 's-component-select', // s-component-*
field: 'sSelect',
label: '下拉框',
props: {
allowClear: true,
placeholder: '请选择',
},
},
{
type: 'ATreeSelect',
slot: '',
field: 'sTreeSelect',
label: '树选择',
props: {
allowClear: true,
showSearch: true,
treeDefaultExpandAll: true,
dropdownMatchSelectWidth: true,
treeNodeFilterProp: 'label',
placeholder: '请选择',
dropdownStyle: {
maxHeight: '300px',
},
treeData: [
{
label: 'A',
value: 'a',
children: [
{
label: 'A-1',
value: 'a-1',
},
{
label: 'A-2',
value: 'a-2',
},
],
},
{
label: 'B',
value: 'b',
children: [
{
label: 'B-1',
value: 'b-1',
},
{
label: 'B-2',
value: 'b-2',
},
],
},
],
},
},
// 第二个 AGroup
{
type: 'AGroup',
slot: '',
field: 'AGroup-2',
label: '日期选择框',
border: true,
},
{
type: 'AYearPicker',
slot: '',
field: 'sYearPicker',
label: '选择年',
props: {
allowClear: true,
format: 'YYYY年',
},
},
{
type: 'AMonthPicker',
slot: '',
field: 'sMonthPicker',
label: '年月',
props: {
allowClear: true,
format: 'YYYY年MM月',
},
},
{
type: 'ADatePicker',
slot: 's-component-date', // s-component-*
field: 'sDatePicker',
label: '年月日',
props: {
allowClear: true,
format: 'YYYY/MM/DD',
valueFormat: 'YYYY-MM-DD',
},
},
{
type: 'AQuarterPicker',
slot: '',
field: 'sQuarterPicker',
label: '季度',
props: {
allowClear: true,
format: 'YYYY年 Q季度',
},
},
{
type: 'ATimePicker',
slot: '',
field: 'sTimePicker',
label: '时间',
props: {
allowClear: true,
format: 'a h:mm',
valueFormat: 'HH:mm',
},
},
])
const rules = formRulesDefiner({
sInput: [{ required: true, message: '请输入内容' }],
sSelect: [{ required: true, message: '请选择 Icon 图标' }],
sDatePicker: [{ required: true, message: '请选择年月日' }],
})
const grid = formGridDefiner({
gutter: 12,
xs: 24,
sm: 12,
md: 8,
})
const model: Ref<any> = ref({
sInput: '这是输入框',
sPassword: '123456',
sSelect: 'AimOutlined',
sCascader: ['ZheJiang', 'NingBo'],
sYearPicker: '2024',
sMonthPicker: '2024-06',
sNumber: 99,
})
</script>
<style lang="less" scoped>
.margin-container {
margin-top: -25px;
margin-bottom: -40px;
}
</style>
API
Props
SForm Props
参数 | 说明 | 类型 | 默认值 |
---|---|---|---|
rules | 表单各组件验证规则,可以被组件的 rlues 覆盖其定义 | object | - |
grid | 表单各组件的布局,可以在 props.groups 里重新定义 | SFormGrid | - |
border | 是否设置 SFormGroupHeader 的 bottom 边框 | string | boolean | - |
groups | 表单各组件配置选项, 有 [Component]、 AGroup、 ARow | Array<object> | [] |
model (v-model) | 表单表单数据对象 | object | - |
disabled | 是否将表单设置禁用 | boolean | false |
readonly | 是否将表单设置只读 (本质还是禁用,只是消除了禁用样式影响) | boolean | false |
spinning | 是否显示表单 loading | boolean | false |
SForm [Component]
参数 | 说明 | 类型 | 默认值 |
---|---|---|---|
type | 表单组件 类型,例:AInput、APassword | SFormType | - |
slot | 表单组件 自定义,例如 slot='input' , 在 SForm 中 <template #s-component-input> 自定义 | string | - |
label | 表单组件 label | string | - |
field | 表单组件 绑定的字段 | string | string[] | - |
grid | 表单组件 布局大小 (24 栅格) | SFormGrid | - |
layer | 表单组件 所应用的 FormItem 的 props | object | {} |
rules | 表单组件 验证规则, 可覆盖 props.rules | object | - |
props | 表单组件 props 定义 | object | {} |
slots | 表单组件 slots 定义,例. 在 AInputSearch 中定义 enterButton 卡槽 | object | {} |
default | 表单组件 数据为空时的默认值 (input -> 传输给表单, output -> 从表单获取) | object | - |
transfer | 表单组件 数据预处理 (input -> 传输给表单, output -> 从表单获取) | object | - |
readonly | 表单组件 是否只读 | boolean | false |
disabled | 表单组件 是否禁用 | boolean | false |
render | 表单组件 是否渲染 | boolean | true |
show | 表单组件 是否显示 | boolean | true |
SForm AGroup
参数 | 说明 | 类型 | 默认值 |
---|---|---|---|
type | 类型 | 'AGroup' | 'AGroup' |
slot | 表单分组 自定义,例如 slot='title' , 在 SForm 中 <template #s-header-title> 自定义 | string | - |
label | 表单分组 标题 | string | - |
border | 设置表单分组 GroupHeader 的 bottom 边框 | string | boolean | {} |
grid | 表单分组下 所属组件 布局大小 (24 栅格) | SFormGrid | - |
readonly | 表单分组下 所属组件 是否只读 | boolean | false |
disabled | 表单分组下 所属组件 是否禁用 | boolean | false |
render | 表单分组下 所属组件 是否渲染 | boolean | true |
show | 表单分组下 所属组件 是否显示 | boolean | true |
SForm ARow
参数 | 说明 | 类型 | 默认值 |
---|---|---|---|
type | 类型 | 'ARow' | 'ARow' |
grid | ARow 所属各组件 布局大小 (24 栅格) | SFormGrid | - |
readonly | ARow 所属各组件 是否只读 | boolean | false |
disabled | ARow 所属下各组件 是否禁用 | boolean | false |
render | ARow 所属下各组件 是否渲染 | boolean | true |
show | ARow 所属下各组件 是否显示 | boolean | true |
Slots
插槽名 | 插槽说明 | 插槽参数 |
---|---|---|
before | 定义 SForm 表单之前内容 | |
after | 定义 SForm 表单之后内容 | |
s-header-* | 定义 SForm 分组内容 | className, group, disabled, readonly |
s-component-* | 定义 SForm 某组件内容 | col, row, group, attrs, slots, disabled, readonly, source, field |
Expose
属性/方法名 | 说明描述 | 类型 |
---|---|---|
resetFields | 对整个表单进行重置,将所有字段值重置为初始值并移除校验结果 | (name?: NamePath) => any |
clearValidate | 移除表单项的校验结果。传入待移除的表单项的 name 属性或者 name 组成的数组 | (name?: NamePath) => any |
getFieldsValue | 获取表单数据,不建议使用。更推荐 v-model,直接通过 model.value 获取 | (nameList?: InternalNamePath[] | true) => any |
scrollToField | 滚动到对应字段位置 | (name: NamePath, options?: any) => any |
validateFields | 触发表单验证 | (nameList?: NamePath[] | string, options?: ValidateOptions) => any |
validate | 触发表单验证 | (nameList?: NamePath[] | string, options?: ValidateOptions) => any |
Definer
定义 | 说明 |
---|---|
formValidator | 预设了表单某组件校验规则,例 password 规则。 详见 Validator |
formGridDefiner | 定义 Props.grid 时的 TypeScript 提示和校验 |
formRulesDefiner | 定义 Props.rules 时的 TypeScript 提示和校验 |
formGroupsDefiner | 定义 Props.groups 时的 TypeScript 提示和校验 |
Validator
目前只预设了 密码(password) 和 数字(number) 校验规则。 当然你也可以自定义校验规则 => 详情
typescript
const rules = formRulesDefiner({
password: formValidator.password({
message: "请输入用户密码",
validator: "用户密码过短",
pattern: /.{8,}/,
required: true,
}),
});
typescript
const rules = formRulesDefiner({
number: formValidator.number({
message: "请输入数字",
validator: "请输入正确的数字",
required: true,
}),
});