跳到主要内容

表单提交策略

策略类型

use hook

在使用扩展 hooks 前,确保你已熟悉了 alova 的基本使用。

为表单提交而设计的 hook,通过此 hook 你可以很方便地实现表单草稿、多页面(多步骤)表单,除此以外还提供了表单重置等常用功能。

示例

表单提交 Demo

特性

  • ✨ 表单草稿;
  • ✨ 多页面(多步骤)表单;
  • ✨ 表单提交自动重置数据;
  • ✨ 手动重置表单数据;

安装

# npm
npm install @alova/scene-vue --save
# yarn
yarn add @alova/scene-vue

使用

基本用法

展示表单 hook 的基本使用。

<template>
<input v-model="form.name" />
<select v-model="form.cls">
<option value="1">class 1</option>
<option value="2">class 2</option>
<option value="3">class 3</option>
</select>
<button
@click="handleSubmit"
:loading="submiting">
提交
</button>
</template>

<script setup>
import { formSubmit } from './api.js';
import { useForm } from '@alova/scene-vue';

const {
// 提交状态
loading: submiting,

// 响应式的表单数据,内容由initialForm决定
form,

// 提交数据函数
send: submit,

// 提交成功回调绑定
onSuccess,

// 提交失败回调绑定
onError,

// 提交完成回调绑定
onComplete
} = useForm(
formData => {
// 可以在此转换表单数据并提交
return formSubmit(formData);
},
{
// 初始化表单数据
initialForm: {
name: '',
cls: '1'
}
}
);

// 提交表单数据
const handleSubmit = () => {
// 验证表单数据...
submit();
};
</script>

useForm默认不会请求,在调用send后才会发出请求,同时在useForm的回调函数将传入最新的 form 数据,如果需要在提交前转换数据,可在此进行转换,也可以在formSubmit函数中转换。

注意
  1. initialForm是设置初始表单数据,initialData是设置初始响应数据,注意区分;
  2. updateForm是更新表单数据,update是更新响应数据,注意区分;

以上示例只展示了简单的表单提交功能,普通的表单提交没有差别,但useForm还实现了更多的实用功能,让我们继续往下看。

提交自动重置表单

很多时候,我们都需要在表单提交后重置表单数据,在自行实现时我们总是需要手动一个一个重新赋值,而useForm可以帮我们自动完成。

useForm(submitData, {
// ...
// 设置这个参数为true即可在提交完成后自动重置表单数据
resetAfterSubmiting: true
});

如果你需要手动重置表单数据,也可以通过调用reset函数做到。

const {
// 表单重置函数
reset
} = useForm(submitData, {
// ...
});

const handleReset = () => {
reset();
};

更新表单数据

在编辑表单时,我们需要展示原表单的数据,此时可以使用updateForm来异步更新表单数据。

const {
// ...
updateForm
} = useForm(submitData, {
// ...
{
// 初始化表单数据
initialForm: {
name: '',
cls: '1'
}
}
});

// 请求表单数据并更新到表单中
const { onSuccess } = useRequest(getData);
onSuccess(({ data }) => {
updateForm({
name: data.name,
cls: data.cls
});
});

表单草稿

useForm还提供了表单草稿功能,在数据重置前即使刷新页面也可以恢复表单数据,其原理是使用 alova 实例上的存储适配器,将表单数据进行持久化。使用时只需要将store设置为 true 即可。

useForm(submitData, {
// ...
// 开启持久化保存数据,设置为true后将实时持久化未提交的数据
store: true
});

数据持久化前将会调用JSON.stringify转换为 JSON 字符串,在默认情况下,表单数据在持久化保存时将会进行数据序列化,useForm内置了DateRegExp实例的序列化,这在使用时间选择器时将很有用。

在表单数据只涉及到DateRegExp实例时你无需进行更多操作,但如果有其他非 JSON 数据时,例如moment实例,我们需要自定义序列化器,不过别担心,自定义序列化器很简单,以下将展示设置一个moment序列化器。

import moment from 'moment';
const momentSerializer = {
// forward在序列化时被调用
// 需要判断是否为moment实例,如果不是目标值则返回undefined,表示不处理它
forward: data => moment.isMoment(data) ? data.valueOf() : undefined,

// backward在反序列化时被调用,data为forward中返回的值
backward: timestamp => moment(timestamp);
};

useForm(
submitData,
{
store: {
enable: true,
serializers: {
moment: momentSerializer
}
}
}
);

多页面/多步骤表单

很多时候我们会遇到表单项分为了多个页面,或多个步骤进行填写,并在最后统一提交的情况,例如多步骤的用户注册、填写问卷等,以及多个步骤的表单可能有相互依赖关系,如果自行实现将会带来一定麻烦。而useForm实现了表单数据共享,你可以在不同的页面或组件中获取到同一份表单数据,解决了多步骤表单数据依赖的问题,也不需要在提交时汇总表单数据,可直接提交。

使用时,你需要通过useForm设置 id,通过相同的 id 你可以在不同页面间共享同一份表单数据。例如我们有一个表单需要经过 3 个步骤填写表单,它们分别会经过组件 A、组件 B、组件 C。

组件A -> 组件B -> 组件C

此时,我们可以在组件 A 内初始化表单数据:

const returnStates = useForm(submitData, {
initialForm: {
step1Input: '',
step2Input: '',
step3Input: ''
},
id: 'testForm'
});
const { form, send } = returnStates;

在组件 B、组件 C 中可直接在第一个参数中传入 id,获取组件 A 内的共享数据。

const returnStates = useForm('testForm');
const { form, send } = returnStates;

组件 B、C 内通过 id 返回的 returnStates 与组件 A 内的 returnStates 是相同的引用,你可以使用同一个 form,也可以在任意一个组件内调用 send 统一提交表单数据。

额外的

在组件 B、C 中直接指定 id 的方式获取共享数据时,这个 id 必须先初始化表单数据,就像在组件 A 中那样,否则将会抛出the form data of id {1} is not initial错误。如果你的多步骤表单并不是按一定顺序,而是根据一定条件随机顺序的,例如:

# 可能的顺序1
组件B -> 组件A -> 组件C

# 可能的顺序2
组件A -> 组件C -> 组件B

# 可能的顺序3
组件C -> 组件A -> 组件B

# ...

在这种情况下,你可以在组件 B、C 中像组件 A 一样使用useForm

const returnStates = useForm(submitData, {
initialForm: {
step1Input: '',
step2Input: '',
step3Input: ''
},
id: 'testForm'
});

这样无论先渲染哪个组件都可以对 id 为 testForm 的表单初始化,后面的组件在遇到 id 为 testForm 时将优先使用已初始化的表单数据,而不会再次初始化。这样你就可以在任意组件内初始化表单数据。

更详细的多步骤表单也可以在表单提交 Demo中体验和查看。

条件筛选

useForm还可以用于对数据筛选场景所用到的筛选表单,例如你希望通过城市名搜索城市信息,你可以设置immedidate=true,它将会在初始化时就开始查询数据,在之后的操作中再调用send重复查询数据。

const { send: searchData } = useForm(queryCity, {
initialForm: {
cityName: ''
},
immediate: true
});
条件限制

在条件筛选场景下,useForm更适用于非分页的列表条件查询,如果你需要在分页列表中进行条件查询,建议使用 分页请求策略(usePagination)

API

Hook 配置

继承useRequest所有配置。

名称描述类型默认值版本
initialForm初始表单数据any--
idform id,相同 id 的 data 数据是同一份引用,可以用于在多页表单时共用同一份表单数据。单页表单不需要指定 idstring | number--
store是否持久化保存数据,设置为 true 后将实时持久化未提交的数据boolean | StoreDetailConfigfalse-
resetAfterSubmiting提交后重置数据booleanfalse-

响应式数据

继承useRequest所有响应式数据。

名称描述类型版本
form表单数据,由 initialForm 决定any-

StoreDetailConfig

名称描述类型默认值版本
enable是否启用持久化数据booleanrequired-
serializers自定义序列化器的集合,内置的序列化器:
1. date 序列化器用于转换日期
2. regexp 序列化器用于转化正则表达式
可以通过设置同名序列化器来覆盖内置序列化器
Record<string | number, DataSerializer>--

DataSerializer

名称描述类型默认值版本
forward序列化函数,forward 中序列化时需判断是否为指定的数据,并返回转换后的数据,否则返回 undefined 或不返回(data: any) => any | undefined | voidrequired-
backward反序列化函数,直接反序列化数据(data: any) => any | undefined | voidrequired-

操作函数

继承useRequest所有操作函数。

名称描述函数参数返回值版本
updateForm更新一项或多项表单数据newForm: Partial<F> | (oldForm: F) => F)
F 为initialForm类型
--
reset重置为初始化数据,如果有持久化数据也会清空---

事件

继承useRequest所有事件。

名称描述回调参数版本
onRestore持久化数据恢复后触发--