1、场景
在实际工作开发中,我们在处理 el-form 表单校验问题时常会遇到这样一种情况:根据不同的条件,展示不同的 el-form-item,这个时候我们就需要考虑表单元素的显示与隐藏。在vue中,控制显示隐藏的有两个指令:v-if 和 v-show。
【1】两者不同点:v-if 是动态的向DOM树内添加或者删除 DOM 元素;v-show 是通过设置 DOM元素的 display 样式属性控制显隐;
【2】原理:v-if 切换有一个局部编译/卸载的过程,切换过程中合适地销毁和重建内部的事件监听和子组件;v-show 只是简单的基于 css 切换;
【3】编译条件:v-if 是惰性的,如果初始条件为假,则什么也不做;只有在条件第一次变为真时才开始局部编译(编译被缓存?编译被缓存后,然后再切换的时候进行局部卸载); v-show 是在任何条件下(首次条件是否为真)都被编译,然后被缓存,而且 DOM 元素保留;
【4】性能消耗:v-if 有更高的切换消耗;v-show 有更高的初始渲染消耗;
【5】使用场景:v-if 适合运营条件不大可能改变;v-show 适合频繁切换。
2、指令的选择
【1】首先我选择使用 v-if 来控制 el-form-item 元素的显示隐藏,但是在使用过程中发现,使用 v-if来控制的 el-form-item 元素,在后续的条件切换显示中,会造成表单校验失效的问题。
【2】由于 v-if 存在表单校验失效的问题,所以后续我又尝试了使用 v-show 来控制,但是 v-show也存在一个问题,就是即使 el-form-item 元素被隐藏了,它的校验也会生效。
原因分析:
【1】使用 v-if:element 在对 form 表单中带有 prop 属性的子组件进行校验规则绑定时,是在 vue声明周期 mounted 完成的。而 v-if 用来切换的元素是会被销毁的,导致了 v-if 内的表单项,由于在 mounted 时期没有进行渲染,所以规则也没有绑定上,因此初始化时不符合显示条件的不会生成规则,导致后面切换条件,显示的输入框的校验不会生效。
【2】使用 v-show:初始化时会生成所有的规则,即使隐藏了也会进行规则校验。
3、解决
查阅相关资料后,发现一个简单粗暴的方法,即给在 v-if 的元素上加上 key 值,便能解决 v-if 带来的表单校验失效的问题,代码如下:
<el-form-item label="选择人员" prop="documentPower">
<el-radio-group v-model="newGroup.documentPower" @change="radioChange">
<el-radio label="1">全员</el-radio>
<el-radio label="2">部门</el-radio>
<el-radio label="3">个人</el-radio>
</el-radio-group>
</el-form-item>
<!-- 部门 -->
<el-form-item label="部门名称" prop="deptIdList" v-if="newGroup.documentPower=='2'" key="deptIdList">
<el-select v-model="newGroup.deptIdList" placeholder="请选择部门" clearable multiple @change="$forceUpdate()">
<el-option v-for="item in dptSelect" :key="item.deptId" :value="item.deptId" :label="item.deptName">
</el-option>
</el-select>
</el-form-item>
<!-- 个人 -->
<el-form-item label="人员" v-else-if="newGroup.documentPower=='3'" prop="people" key="people">
<el-input v-model="newGroup.people" @focus="openSelectUser" type="textarea"></el-input>
</el-form-item>
原因:因为在 v-for 或者 v-if 切换标签时,多个相同的标签被渲染,如果不添加key来区分则会出现复用的情况。而原本这些标签每一个都是独立的,所以需要添加 key 来做区分。
即使在不是 v-for 中的表单,我们经常会遇到通过条件渲染部分表单验证,并且表单之间还有联动性,比如一个勾选某个checkbox 后面会相应的显示相关部分的表单,不勾选则隐藏,校验的时候也会出问题,所以解决方法就是给每个 form-item 加上 key 属性