分享一个使用element-plus的el-form表单组件时,字段显示与校验和重置的问题
标题可能有点绕哈,我来解释一下使用场景,我们在使用el-form组件时,通常会有新增和编辑两种场景,并且通常会复用一个表单组件用来编辑和新增。但是这时候往往一些新手同学会遇到一个问题,就是如果我们先新增,再编辑,resetFields方法可以正常生效,但先点编辑,再点新增,resetFields方法就会失效,编辑完再新增依然会残留上一次编辑时的数据。
这是因为Element UI Plus(含Element UI,本文使用的是plus)的一个设计缺陷,它在第一次渲染表单项时会记录“初始值”,而我们在编辑的时候可能会错误的把表单显示和赋值同时进行,这时候element就会误以为编辑的值就是初始值,所以使用resetFields方法进行重置就会失效,甚至就算我们把某些字段清空,再打开表单弹框,依然显示的是上一次的编辑值。
这个问题很好解决,我们在编辑的时候,先让弹窗显示,然后再进行赋值即可,也就是先把弹窗的显示条件改为true,然后使用vue的nextTick(关于nextTick的用法可自行搜索)方法待弹窗渲染完成之后再进行赋值就没问题啦。
上面说的可以解决最基本的需求,我这次写页面也是这样做的,但昨晚突然发现了新的问题。因为我还有进一步的需求,就是我的表单里的某些字段是需要特定条件才显示的,就比如添加菜单时,类型可能有菜单、页面和按钮三种类型,他们分别有自己的专属字段,就像下面这样
因为每个类型有自己的专属字段,这些字段的校验仅在当前类型下生效,就比如权限标识的校验显然不能再添加页面时生效,我首先想到的是对字段用v-if,这样确实达到了我期待的效果,每个类型的字段校验都仅在当前校验下生效。
但同时也发现了新的问题,就是虽然我用了nextTick,但是表单第一次展示还是无法渲染所有字段,不知道我描述的够不够清楚。啰嗦几句,就是我第一次展示弹窗,使用了nextTick,弹窗显示,这时候菜单类型为菜单,所以菜单下的这些字段都会被正常渲染,初始值夜完全正确,但是页面和按钮下面的字段是没有渲染的,当我切换菜单类型为页面时,element会渲染属于页面类型的专属字段,由于某些字段已经存在了(比如页面下的模板地址),element就会错误的认为这些值就是初始值。
至于为什么一个菜单类型的数据会有页面类型的字段,那就是我比较懒,不会再切换他的类型时清空不属于当前类型的值,比如这条数据最开始时是页面,拥有模板地址字段,后来我给这条数据改为菜单类型了,模板地址字段也没清空,反正也不会生效。
接上面说啊,当我们切换菜单类型时,这些已经存在的值就会被当做初始值,从而无法被resetFields方法重置,按照最上面说的方法,我们需要在现实菜单的时候,给菜单类型的字段赋值,显示页面类型的时候,给页面类型的数据赋值,但这样显然相当繁琐,与其这样,我们还不如手动给字段赋空值来得快。
要解决这个问题,显然需要让这些字段在第一次nextTick时就全部渲染,那么显然我们的v-if就不能用了。得用v-show进行替代。这样虽然行得通,但是我们不要忘了我们使用v-if的最初目的,那就是让每个类型的字段仅在当前类型下生效。现在v-if没了,那字段验证怎么办?
于是经过我查找资料,又了解到了一种思路,那就是动态规则验证。既然我们无法使用v-if来阻止表单校验了,那我们让其他类型的字段校验在选中当前类型时消失不就好了?
于是我对rules进行了改造,对rules的每个字段规则加上了和字段一样的判断,并从常规变量改为了computed,因为常规变量不会随着判断条件的改变而改变,于是我的代码就从
// 节选部分字段
const rules = reactive<FormRules>({
path: [
{
required: true,
message: '请输入访问路径',
trigger: ['blur', 'change'],
},
],
})
变成了
const rules = computed<FormRules>(() => {
path:
formContent.menuType !== '3' // 与path字段的显示规则一致
? [
{
required: true,
message: '请输入访问路径',
trigger: ['blur', 'change'],
},
]
: [],
})
这样是解决了我的问题,可我又遇到了新的问题,就是每次我切换菜单类型(也就是变更字段的显示条件)时,表单的校验规则都会被触发一下,谁都不会想看到什么都还没输入呢,输入框就变红的场景。于是看了官方文档,发现了el-form有一个属性叫validate-on-rule-change,解释是是否在 rules
属性改变后立即触发一次验证,默认值是true
,我们给改为false即可。现在就完美啦。
不过对于我来说,还有一丢丢的小问题,那就是我有些字段是复用的,比如我的菜单名称和页面名称用的是一个字段,只不过在切换类型的时候改了一下名字。这样的问题就是,如果我在添加菜单时对名称进行了校验,然后校验没通过,切换到页面类型,这个字段依然会呈现校验失败的状态,于是我还需要在每次切换菜单类型时调用一下clearValidate()方法对校验状态重置一下,这下子就没问题啦。
总结:这个问题难度不大,就是有点偏门,不知道能不能对大家进行帮助,写下来也算是自己的一个小笔记吧,以后自己忘了还可以翻翻。问题虽然不难,但稍微有些复杂,所以写的啰嗦了一点,看不懂没问题,可以留个印象,当你日后遇到同样的问题时再带着问题来看,相信会有水到渠成的效果。