下拉框为必录字段,要求下拉框隐藏时不触发校验规则。问题:隐藏时候总是触发校验规则
问题
下面是省份公司显示时候的页面展示:
省份公司的下拉框隐藏时候,如页面所示,点击查询,还是有提醒文字
代码如下:
<el-form-item prop="province"> <el-select v-if="visibility.province" v-model="searchQuery.province" placeholder="省分公司:" clearable> <el-option v-for="item in provinceOptions" :key="item.id" :value="item.label" :label="item.label"></el-option> </el-select> </el-form-item>
通常,如果一个输入组件(例如 <el-select>
)使用 v-if
来控制显示和隐藏,当 v-if
为 false
时,相关的 DOM 元素会被移除,与之绑定的验证规则也不会触发。但是可能用的版本实在太老,需要再手动调整校验触发规则
解决
方案一(clearValidata失败)
在验证之前手动清除要隐藏的选择框的验证状态:
handleSearch() { if (!this.visibility.province) { this.$refs.searchQuery.clearValidate('province'); } if (!this.visibility.city) { this.$refs.searchQuery.clearValidate('city'); } if (!this.visibility.vendor) { this.$refs.searchQuery.clearValidate('vendor'); } this.$refs.searchQuery.validate((valid) => { if (valid) { // 处理表单提交 } else { // 处理验证错误 } }); }
通过 clearValidate
方法清除了不可见元素的验证状态。但是不好使
方案二 (:prop失败)
- 动态设置表单项的
prop
属性,仅当元素可见时绑定,当隐藏时解绑属性:
<el-form-item :prop="visibility.province ? 'province' : null"> <el-select v-if="visibility.province" v-model="searchQuery.province" placeholder="省分公司:" clearable> <!-- options --> </el-select> </el-form-item>
确保仅当 visibility.province
为真时,才会对 province
应用验证规则。
但是,用这个方法即使在省份下拉框显示的时候,校验规则依然不触发,并且当其他必录校验规则满足,直接可以提交成功,也就是说,这个字段直接失去校验了,如图:
方案三:
(:rules成功)
v-if
控制了下拉框组件是否被渲染到页面上。采用 :rules
属性则是指向一个数组,用于设定下拉框的校验规则。在隐藏该下拉框时,将 rules
属性设置为一个空数组,以移除校验规则:
<el-form-item prop="province" :rules="visibility.province ? province : []"> <el-select v-if="visibility.province" v-model="searchQuery.province" placeholder="省分公司:" clearable> <el-option v-for="item in provinceOptions" :key="item.id" :value="item.label" :label="item.label"></el-option> </el-select> </el-form-item>
思考
为什么前两种方法不行,我目前的环境是vue2+element-ui2.4.4
方案 1: 使用 clearValidate
清除验证状态
这种方法适用于动态更改表单字段可见性时,因为它可以清除之前可能已经应用到这些字段的验证结果。然而,这种方法并不会移除字段的验证规则,它只是重置验证状态。如果字段变得不可见,但由于某种原因,在验证逻辑触发时,字段依旧被 Element UI 的验证逻辑所考虑,那么仍会出现问题。
方案 2: 动态设置 prop
这种方法通过条件绑定来决定 el-form-item
是否参与验证。理论上,如果没有指定 prop
,那么 Element UI 就不会去验证这个表单项。如果这个方法没有成功,可能是因为 visibility
对象状态在验证逻辑触发前没有正确更新,或者 Element UI 内部的验证器不完全依赖 prop
来判断是否应该验证该字段。
方案 3: 动态设置 rules
这是直接操纵验证规则本身。通过将 :rules
绑定为一个可以动态更新的数组,我们可以完全控制何时以及如何验证每个字段。当不想要验证时,简单地为 :rules
分配一个空数组 ([]
) 即可。
为什么方案 3 成功,而前两种失败了
可能的原因包括:
-
Element UI 的验证机制:Element UI 可能在内部处理
prop
和rules
的方式上有所不同,规则的存在可能是验证逻辑的主要触发条件。如果你没有从校验规则中移除字段,验证逻辑仍可能考虑这些字段。 -
Vue 的响应式系统细节:也可能是因为在 Vue2 中,对于对象属性的添加或删除,需要使用
$set
或$delete
来保证它们是响应式的,尤其是当你在组件的data
对象以外创建对象的时候。 -
组件状态更新的时序问题:可能存在的另一个问题是状态更新和验证逻辑的触发之间的时序问题。如果
visibility
的更新或者prop
的更改在验证逻辑后发生,那么验证规则的应用状态可能不如预期。
方案 2 和方案 3 的区别
虽然表面上看来方案 2 和方案 3 都是动态控制验证,但实质上方案 3 提供了更细粒度的控制:
- 方案 2 基于
prop
的存在与否来决定是否验证这个字段,没有prop
就意味着没有验证规则。 - 方案 3 更为直接和灵活,能够动态地给定任何规则集合,甚至可以在运行中修改具体的规则。它不仅仅是关于验证,还可以准确指定任何时点上特定字段的验证逻辑应该是什么。
综上,若方案 1 和方案 2 都未能奏效,推荐的办法是继续使用方案 3,即动态修改 rules
,这是最直接、最灵活也是最可靠的方法来控制下拉框的验证行为。而 Elemental UI 可以确保只有为 :rules
提供了规则时,对应的字段才会被验证。如果组件的状态更新和清除规则发生在验证之前,这应该会确保不可见的字段不会触发任何验证。
补充
新问题,点击查询之后仍有问题提醒
添加监听器
watch:{ 'searchQuery.province'(newValue, oldValue) { if (newValue !== oldValue) { // this.$nextTick(() => { this.$refs.searchQuery.validateField('province'); }); // } }, 'searchQuery.city'(newValue, oldValue) { if (newValue !== oldValue) { // this.$nextTick(() => { this.$refs.searchQuery.validateField('city'); // }); } }, 'searchQuery.vendor'(newValue, oldValue) { if (newValue !== oldValue) { // this.$nextTick(() => { this.$refs.searchQuery.validateField('vendor'); // }); } } },
注释掉$nextTick的原因:
关于this.$nextTick(() => { ... });
这行代码,在Vue.js中它被用来将其内容的执行延迟到下一个DOM更新周期。当你在数据变化后想立即操作或访问DOM时,这非常有用。
在代码上下文中,这行代码存在与否有如下不同:
-
使用
this.$nextTick()
: 通过使用this.$nextTick()
,确保了province
字段的验证在Vue更新DOM之后进行。如果验证过程依赖于DOM与最新变化同步,这是很重要的。但是: -
-
不使用
this.$nextTick()
:-
即省份下拉框DOM渲染后,不立刻触发校验只有检测到下拉框的值不等于之前的空值之后再触发
-