import {...,onMounted } from 'vue' ... onMounted(()=>{ setTimeout(()=>{ dynamicValidateForm.email = '1372978934@qq.com' },200) }) ...问题分析
const resetForm = (formEl: FormInstance | undefined) => { if (!formEl) return formEl.resetFields() }我们找到源码的form文件夹下的form.vue文件,并找到对应的resetFields方法定义,可以看到它执行了一个方法名称为resetField的函数
const resetFields: FormContext['resetFields'] = (properties = []) => { if (!props.model) { debugWarn(COMPONENT_NAME, 'model is required for resetFields to work.') return } filterFields(fields, properties).forEach((field) => field.resetField()) }我们按照引用路径,找到form-item.vue文件,并找到resetField方法定义。可以看出,它从form表单上下文对象上根据表单上设置的prop找到对应的属性,getProp拿到的应当是当前的最新的表单项的值,接着它直接使用initialValue对该computedValue进行了覆盖。
const resetField: FormItemContext['resetField'] = async () => { const model = formContext?.model if (!model || !props.prop) return const computedValue = getProp(model, props.prop) // 堆代码 duidaima.com // prevent validation from being triggered isResettingField = true computedValue.value = clone(initialValue) await nextTick() clearValidate() isResettingField = false }所以问题的关键就是initialValue是什么?initialValue是当前文件下的一个全局变量,并且它在onMounted中被设置了初始值
let initialValue: any = undefined onMounted(() => { if (props.prop) { formContext?.addField(context) initialValue = clone(fieldValue.value) } })看到这里我想你应该就明白了,由于form表单是作为业务组件的子组件,因此它会比业务组件早patched,这就意味着,这里的onMounted会先被执行,我们后续设置的值对element的form来说并不作为初始值被认可,因此,我好像冤枉人家element-plus了,根本原因好像是我们自己写的代码有问题。
onBeforeMount(()=>{ dynamicValidateForm.email = '1372978934@qq.com' })可是,我这是需要从后台拉取的数据,是异步的,我怎么保证它比业务组件快呢?可能有些人会说了,你async一下不就完了嘛
onBeforeMount(async ()=>{ dynamicValidateForm.email = await fetchValue() }) const fetchValue = async ()=>{ return new Promise((resolve)=>{ resolve('1372978934@qq.com') }) }
人家vue凭什么要为你埋单呢???所以啊,我们还是需要把他当成一个bug来处理的!!!(ps:开发期间为了优先完成任务我的做法是自己在内部缓存一份初始值,然后手动的进行重新设置)。
npx patch-package element-plusvue独享
delete FormItem.mounted const FormItemPatched = { extends: FormItem, mounted() { if (props.prop) { formContext?.addField(context) initialValue = clone(fieldValue.value) window.onstorage = (payload)=>{ initialValue = payload } } }, }如此一来,我们就可以在业务组件中通过localStorage.setItem来将初始值传递给form-item内部了
localStorage.setItem('somekey',initialValue)
这个方案几乎是完美的,我们只需要在我们当前这一个页面调用Vue.component进行注册,它就既能解决我们当下的问题,又不会影响到element-plus后续的更新。