Skip to content

Commit

Permalink
fix(Form): 异步表单校验支持 (#496)
Browse files Browse the repository at this point in the history
* refactor(Form): 增加校验失败日志信息

* fix(Form): 异步表单校验支持

* fix(Form): 表单校验信息打印支持多级表单域的情况
  • Loading branch information
ocean-gao authored Nov 1, 2023
1 parent 18839e5 commit 42798f2
Show file tree
Hide file tree
Showing 5 changed files with 209 additions and 14 deletions.
6 changes: 5 additions & 1 deletion components/form/formItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,11 @@ export default defineComponent({
const error = errObj.errors[0];
setValidateInfo(VALIDATE_STATUS.ERROR, error.message);
return Promise.reject([
{ ...error, message: error.message },
{
...error,
message: error.message,
descriptor: descriptor[formItemProp.value] || null,
},
]);
}
}
Expand Down
184 changes: 184 additions & 0 deletions docs/.vitepress/components/form/asyncValidator.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
<template>
<FForm
ref="formRef"
labelWidth="140px"
labelPosition="right"
:model="modelForm"
:rules="rules"
>
<FFormItem prop="name" label="实时校验">
<FInput
v-model="modelForm.name"
placeholder="请输入姓名"
:maxlength="30"
showWordLimit
></FInput>
<LoadingOutlined
v-show="modelForm.nameLoading"
style="margin-left: 10px"
/>
</FFormItem>
<FFormItem prop="phone" label="防抖校验">
<FInput
v-model="modelForm.phone"
placeholder="请输入手机号"
:maxlength="11"
showWordLimit
></FInput>
<LoadingOutlined
v-show="modelForm.phoneLoading"
style="margin-left: 10px"
/>
</FFormItem>
<FFormItem label=" ">
<FButton
type="primary"
style="margin-right: 20px"
:loading="modelForm.submitLoading"
@click="submitHandler"
>
{{ modelForm.submitText }}
</FButton>
<FButton
type="primary"
style="margin-right: 20px"
@click="clearHandler"
>
清除
</FButton>
<FButton type="primary" @click="resetHandler">重置</FButton>
</FFormItem>
</FForm>
</template>

<script>
import { ref, reactive, computed } from 'vue';
// eslint-disable-next-line import/no-unresolved
import { debounce } from 'lodash-es';
import { FMessage } from '@fesjs/fes-design';
function sleep(time) {
return new Promise((resolve) => setTimeout(resolve, time));
}
export default {
setup() {
const formRef = ref(null);
const modelForm = reactive({
submitLoading: false,
submitText: '提交',
name: '',
nameLoading: false,
phone: '',
phoneLoading: false,
});
const debounceValidator = debounce(async (value, resolve, reject) => {
console.log(
'[form.asyncValidator] [debounceValidator] phone:',
value,
);
modelForm.phoneLoading = true;
await sleep(2000);
if (value.length < 11) {
reject('异步校验手机号不完整');
} else {
resolve();
}
modelForm.phoneLoading = false;
}, 300);
const rules = computed(() => {
return {
name: [
{
required: true,
message: '姓名不能为空',
},
{
asyncValidator: (rule, value) => {
return new Promise(async (resolve, reject) => {
if (!value) {
return reject('异步校验姓名不能为空');
}
console.log(
'[form.asyncValidator] [asyncValidator] name:',
value,
);
modelForm.nameLoading = true;
await sleep(3000);
modelForm.nameLoading = false;
if (value.length < 3) {
return reject('异步校验姓名字符个数不足');
} else {
return resolve();
}
});
},
message: '姓名至少三个字符长度',
trigger: ['change'],
},
],
phone: [
{
required: true,
message: '手机号不能为空',
},
{
asyncValidator: (rule, value) => {
return new Promise(async (resolve, reject) => {
if (!value) {
return reject('异步校验手机号不能为空');
}
debounceValidator(value, resolve, reject);
});
},
message: '手机号不完整',
trigger: ['change'],
},
],
};
});
const submitHandler = async () => {
try {
modelForm.submitLoading = true;
modelForm.submitText = '校验中';
const result = await formRef.value.validate();
console.log(
'[form.validate] [submitHandler] 表单验证成功, result:',
result,
);
} catch (error) {
console.log(
'[form.validate] [submitHandler] 表单验证失败, error:',
error,
);
FMessage.warn('请检查表单项');
} finally {
modelForm.submitLoading = false;
modelForm.submitText = '提交';
}
};
const clearHandler = () => {
formRef.value.clearValidate();
};
const resetHandler = () => {
formRef.value.resetFields();
};
return {
formRef,
modelForm,
rules,
submitHandler,
clearHandler,
resetHandler,
};
},
};
</script>
<style scoped></style>
29 changes: 18 additions & 11 deletions docs/.vitepress/components/form/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ align.vue
disabled.vue
:::

### 表单验证
### 常规表单验证

Form 组件提供表单验证的功能,通过 rules 属性传入约定的验证规则,并将 FormItem 的 prop 属性设置为需校验的字段名即可。表单验证目的在于尽可能让用户更早地发现并纠正错误。

Expand All @@ -60,12 +60,18 @@ validate.vue
complexValidate.vue
:::

### 异步表单验证

:::demo
asyncValidator.vue
:::

## Form Props

| 属性 | 说明 | 类型 | 默认值 |
| --------------- | --------------------------------------------------------------- | -------------------------- | ------------ |
| model | 表单数对象 | object | - |
| rules | 表单验证规则,可查看`async-validator` | object | - |
| rules | 表单验证规则,可查看`Form-Item Rule Type` | object | - |
| layout | 表单布局,可选值为`horizontal``inline` | string | `horizontal` |
| inlineItemWidth | 仅在 `inline` 表单中有效。统一定义 FormItem 固定宽度 | string、number | - |
| inlineItemGap | 仅在 `inline` 表单中有效。统一定义整行 FormItem 的间距 | string、number | 11px |
Expand Down Expand Up @@ -119,12 +125,13 @@ complexValidate.vue
## Form-Item Rule Type

以下并不是规则的全部用法,如果你想了解更多的用法,请参考 <a href="https://github.com/yiminghe/async-validator" target="blank">async-validator </a>。
| 属性 | 说明 | 类型 | 默认值 |
| ------------- | ------------- | ------------- | ------------- |
| trigger | 校验触发的时机 | string、Array | - |
| required | 是否必填 | boolean | false |
| message | 校验失败时展示的信息 | string | - |
| type | 内建校验类型,<a href="https://github.com/yiminghe/async-validator#type" target="blank">可选项</a> 【注意: 非`string`类型都需要指明 type】 | string | 'string' |
| min | 最小长度 | number | - |
| max | 最大长度 | number | - |
| validator | 自定义校验【注意,<a href="https://github.com/ant-design/ant-design/issues/5155" target="blank">callback 必须被调用】</a> | function(rule, value, callback) | - |

| 属性 | 说明 | 类型 | 默认值 |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------- | -------- |
| trigger | 校验触发的时机 | string、Array | - |
| required | 是否必填 | boolean | false |
| message | 校验失败时展示的信息 | string | - |
| type | 内建校验类型,<a href="https://github.com/yiminghe/async-validator#type" target="blank">可选项</a> 【注意: 非`string`类型都需要指明 type】 | string | `string` |
| min | 最小长度 | number | - |
| max | 最大长度 | number | - |
| validator | 自定义校验【注意,<a href="https://github.com/ant-design/ant-design/issues/5155" target="blank">callback 必须被调用】</a> | function(rule, value, callback) | - |
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@
"@types/lodash-es": "^4.17.5",
"@vue/shared": "^3.2.24",
"@vueuse/core": "^9.6.0",
"async-validator": "^4.0.7",
"async-validator": "^4.2.5",
"csstype": "^3.0.10",
"date-fns": "^2.28.0",
"lodash-es": "^4.17.21",
Expand Down
2 changes: 1 addition & 1 deletion pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 42798f2

Please sign in to comment.