处理逻辑联动
在复杂表单中,经常会遇到字段之间的联动需求,例如“当选择了某个选项时,才显示另一个输入框”,或者“根据某个选项动态更改后续字段的配置”。
利用 @qin-ui/core 的 useForm,你可以轻松监听 form.formData 的变化,并通过 form.setField 响应式对象来实现联动。
表单展示
表单数据对象:{}
代码实现
vue
<script lang="ts" setup>
import { computed, h, ref, watch } from 'vue';
import { Button, Radio, Space } from 'vant';
import { ProForm, useForm } from '@qin-ui/vant-pro';
type FormData = {
maritalStatus: string;
spouseName: string;
spouseAge: number;
spousePhone: string;
};
const spouseAgeHidden = ref(true);
const form = useForm<FormData>({}, [
{
path: 'maritalStatus',
label: '婚姻状况',
component: 'radio-group',
direction: 'horizontal',
slots: {
default: () => [
h(Radio, { name: 'married' }, () => '已婚'),
h(Radio, { name: 'unmarried' }, () => '未婚'),
],
},
onChange: () => {
setFormData(({ maritalStatus }) => ({ maritalStatus }));
spouseAgeHidden.value = formData.maritalStatus !== 'married';
},
},
{
path: 'spouseName',
label: '配偶姓名',
component: 'field',
// 方式1. 使用 vue computed 进行依赖关联
hidden: computed((): boolean => formData.maritalStatus !== 'married'),
},
{
path: 'spouseAge',
label: '配偶年龄',
component: 'stepper',
// 方式2. 使用 vue ref 进行依赖关联
hidden: spouseAgeHidden,
},
{
path: 'spousePhone',
label: '配偶联系方式',
component: 'field',
type: 'tel',
},
]);
const { formRef, formData, setFormData, setField } = form;
watch(
() => formData.maritalStatus,
val => {
// 方式3. 使用 vue watch 动态调整字段配置
setField('spousePhone', { hidden: val !== 'married' });
},
{ immediate: true }
);
const reset = () => {
formRef.value?.resetValidation();
setFormData({});
};
const submit = async () => {
await formRef.value?.validate();
console.log('表单提交数据:', { ...formData });
};
</script>
<template>
<div class="demo-wrapper">
<ProForm :form="form">
<div style="margin: 16px">
<Space>
<Button @click="reset">重置表单</Button>
<Button type="primary" native-type="submit" @click="submit"
>提交</Button
>
</Space>
</div>
</ProForm>
<br />
<div style="padding: 16px; font-size: 14px; white-space: pre">
表单数据对象:{{ formData }}
</div>
</div>
</template>
<style scoped>
.demo-wrapper {
max-width: 430px;
padding: 16px;
overflow: hidden;
background: #f7f8fa;
border-radius: 8px;
}
</style>