项目场景:
项目当中用了 vben 框架, vben 是基于 ant design 封装的,项目中有个需求是一个筛选表单,其中筛选条件中通过下拉列表来完成,两个筛选下拉列表有着联动关系
上图是期望的实现结果,客户和工地有着层级关系,当客户切换,对应工地列表会重新加载,而且选中状态清空,其他的选项不变
问题描述
这里在写的时候,一开始的思路是在所属客户的选中事件中清空工地这个字段的值
但是 vue3 + ts 是真的真的不熟悉啊啊啊啊
总之来看看代码叭
<div class="bg-white mb-2 p-4">
<BasicForm @register="registerForm" ref="formRef" />
</div>
//过滤表单相关的代码
const searchSchemas: FormSchema[] = [
{
field: 'state',
***ponent: 'Select',
label: '设备状态',
colProps: { span: 4 },
***ponentProps: {
allowClear: true,
dictType: 'bu_device_status',
},
},
{
field: 'name',
***ponent: 'Input',
colProps: { span: 4 },
label: '设备名称',
***ponentProps: {
allowClear: true,
},
},
{
field: 'number',
***ponent: 'Input',
colProps: { span: 4 },
label: '设备编号',
***ponentProps: {
allowClear: true,
},
},
{
field: 'customerId',
***ponent: 'Select',
label: '设备所属客户',
colProps: { span: 4 },
***ponentProps: {
allowClear: true,
onChange: handleCustomerChange, // 这里是自己定义了一个函数,当客户状态改变后执行的
options: customerOptions, // customerOptions 是在某个方法中获取到了客户列表的数据
},
},
{
field: 'siteId',
***ponent: 'Select',
label: '设备所属工地',
colProps: { span: 4 },
***ponentProps: {
allowClear: true,
options: siteOptions,
}
}
];
下面这里是清空工地下拉列表的相关代码, updateSite
是在 handleCustomerChange
函数中执行的函数
但是这里发现另一个问题 : 用 setFieldsValue 只设置 siteId 这一个字段为空的时候,整个表单全都被清空了
解决方案,在需要设置 siteId 为空之前,先将所有字段当前的值全部都取出来,然后在设置 siteId 的时候再将所有的数据全部再赋值给对应的字段
// 这里定义一个 formRef 对象,是响应式的 ,然后表单对象当中用 ref 来绑定上
const formRef = ref<any>();
// 以下注释掉的全部都是错误的写法,同样踩雷的可以避一避哈哈哈
const updateSite = (customerId: string, siteOptionsArr: Array) => {
console.log('try to clear site');
// console.log(searchSchemas)
// this.$refs[siteIdRef].resetFields(); // 找不到 refs 啥的
// searchSchemas.resetFields() //resetFields 不是个函数啥的
// this.props.form.resetFields();
// siteIdRef.current?.resetFields();
console.log(formRef.value);
// formRef.value.setFieldsValue({})
const searchObj = ref<any>(formRef.value.getFieldsValue()); // 这里是获取当前过滤表单中的所有字段的值
// console.log(searchObj.value.state)
// console.log(searchObj.value.name)
// console.log(searchObj.value.number)
// 将 siteId 字段的值设置为 " " ,但是这里把其他的字段都取出来又再设置回去的原因是 : 发现当只设置 siteId 这一个字段为空的时候,整个表单全都被清空了
formRef.value.setFieldsValue({state:searchObj.value.state,name:searchObj.value.name,number:searchObj.value.number,siteId: ''})
// setTimeout(() => {
// form.setFieldsValue({
// personName: obj.personName,
// })
// }, 0)
// formRef.value.setFieldsValue(siteId, '')
// formRef.value.resetFields('siteId');
// resetSite();
// formRef.current?.resetFields();
// searchSchemas.setFieldsValue({username: n})
// setFieldsValue
// valiDate.siteId = ''
// siteIdRef.value.resetFields()
console.log('真的重置了吗');
siteOptionsArr.length = 0;
ConstructionSitList({
organizationId: customerId,
}).then((res) => {
console.log('res', res);
res.list.forEach((element) => {
siteOptionsArr.push({ value: element.organizationId, label: element.name });
});
});
console.log(siteOptionsArr);
// return s/
};
下面这张图就是一次次试代码 , 就当看看笑话吧 ,哈哈哈 真的是语法都不知道,全靠蒙
原因分析:
主要有点坑的是 setFieldsValue 来设置某个字段的时候其他的字段会被清空
更加优化一点的方案
在上面的解决思路中,假设表单中有 n 个字段,只有一个需要清空,通过 getFieldsValue 取出来之后,一个个放到 setFieldsValue 中的,但是如果表单中的字段有 20 个呢?
const searchObj = ref<any>(formRef.value.getFieldsValue()); // 这里是获取当前过滤表单中的所有字段的值
//这里一个个放 emmm 其实有更优雅的方式
formRef.value.setFieldsValue({state:searchObj.value.state,
name:searchObj.value.name,
number:searchObj.value.number,
siteId: ''})
以下是优化方案
// 这里获取到了用户选中的客户,这时候首先清空工地列表,然后把工地列表查出来
// 先获取当前表单中的内容
const searchObj = ref<any>(formRef.value.getFieldsValue());
// 通过 JSON.parse = > JSON.stringify 来讲对象深拷贝
const temp = JSON.parse(JSON.stringify(searchObj.value));
// 如果当前的 siteId 不为空,设置成空的
if (temp.siteId !== undefined) {
temp.siteId = '';
}
// 表单中的字段只有 siteId 被清空,剩下的字段还在 temp 当中,再赋值给表单
//(因为执行 setFieldsValue 之后,会导致除了设置的字段以外的整个表单清空)
formRef.value.setFieldsValue({ ...temp });