使用el-form自定义校验的同时使用v-if/v-show引起的校验问题

有时候需要根据不同的条件来回显具体的内容,这时候就会用到v-if/v-show,此时表单的校验就可能会出现一些问题。
比如:使用v-if的时候,明明切换到了另一个条件,但是对应元素的表单校验却没有生效;使用v-show的时候,明明隐藏了某个条件元素,但是该元素的表单校验却依旧存在。

<el-form :model="ruleForm" status-icon :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">
  /*
  	使用v-if进行判断,当初始化的时候条件不满足,则不会被渲染。
  	而element-ui在对form表单中带有prop属性的子组件进行校验规则绑定时,
  	是在Vue声明周期mounted完成的,即就算后续改变了isShowPassWord值也不会实现表单校验。
  	此时只需要给对应的元素添加一个key值即可解决校验不生效的问题。
  */
  <el-form-item label="密码" prop="pass" v-if="isShowPassWord" key="pass">
    <el-input type="password" v-model="ruleForm.pass" autocomplete="off"></el-input>
  </el-form-item>
  /*
  	使用v-show进行判断,即使一开始不满足回显条件依旧会被渲染,只是看不见而已,
  	所以这时候当该组件没有值或者不满足被校验的条件时就会被校验住,不允许提交,
  	此时可以考虑换成v-if进行判断,或者进行自定义校验。
  */
  <el-form-item label="确认密码" prop="checkPass" v-show="isShowCheckPass">
    <el-input type="password" v-model="ruleForm.checkPass" autocomplete="off"></el-input>
  </el-form-item>
  /*
  	在实际应用中通常会有v-model和prop不相同的情况,这时候仍旧需要进行表单校验,则可以使用自定义校验。
  	在自定义校验中不论哪种情况都需要调用callback函数,否则则不会进行后续内容。
  */
  <el-form-item label="年龄" prop="age">
    <el-input v-model.number="ruleForm['age_value']" ref="ageValue"></el-input>
  </el-form-item>
  <el-form-item>
    <el-button type="primary" @click="submitForm('ruleForm')">提交</el-button>
    <el-button @click="resetForm('ruleForm')">重置</el-button>
  </el-form-item>
</el-form>
<script>
  export default {
    data() {
      var checkAge = (rule, value, callback) => {
        /*
        	因为此时的v-model和prop的字段是不一样的,所以这里的value不再是该元素输入的内容了而是空。
        	这个时候可以通过获取元素或者使用ref进行对应元素的内容获取再进行相关的条件判断,然后决定是否通过校验。
        */
        const ageValue = this.$refs.ageValue.value
        if (!ageValue) {
          return callback(new Error('年龄不能为空'));
        }
        setTimeout(() => {
          if (!Number.isInteger(ageValue)) {
            callback(new Error('请输入数字值'));
          } else {
            if (ageValue < 18) {
              callback(new Error('必须年满18岁'));
            } else {
              callback();
            }
          }
        }, 1000);
      };
      var validatePass = (rule, value, callback) => {
        if (value === '') {
          callback(new Error('请输入密码'));
        } else {
          if (this.ruleForm.checkPass !== '') {
            this.$refs.ruleForm.validateField('checkPass');
          }
          callback();
        }
      };
      var validateCheckPass = (rule, value, callback) => {
        if (value === '') {
          callback(new Error('请再次输入密码'));
        } else if (value !== this.ruleForm.pass) {
          callback(new Error('两次输入密码不一致!'));
        } else {
          callback();
        }
      };
      return {
        isShowPassWord: true,
        isShowCheckPass: true,
        ruleForm: {
          pass: '',
          checkPass: '',
          age_value: ''
        },
        rules: {
          pass: [
            { validator: validatePass, trigger: 'blur' }
          ],
          checkPass: [
            { validator: validateCheckPass, trigger: 'blur' }
          ],
          age: [
            { validator: checkAge, trigger: 'blur' }
          ]
        }
      };
    },
    methods: {
      submitForm(formName) {
        this.$refs[formName].validate((valid) => {
          if (valid) {
            alert('submit!');
          } else {
            console.log('error submit!!');
            return false;
          }
        });
      },
      resetForm(formName) {
        this.$refs[formName].resetFields();
      }
    }
  }
</script>

其他文章:
v-if/v-show中使用el-form表单校验,解决校验不生效的问题
Vue+Element中的 el-form-item 进行表单验证时 使用 v-if 出现的问题
vue el-form v-if 自定义表单校验失效

<think>好的,我现在需要解决用户在使用el-form时,结合v-if出现的“Cannot read properties of null (reading 'getBoundingClientRect')”错误的问题。首先,我得回忆一下这个错误的常见原因。用户提到的是在el-form使用v-if时出现的,可能和组件的渲染时机有关。 我记得Element UI或者Element Plus中的表单组件可能会在初始化时进行一些DOM操作,比如校验或者布局计算。当使用v-if控制el-form的显示隐藏时,如果条件初始为false,组件不会被渲染到DOM中,这时候如果尝试访问其DOM元素,就会因为不存在而报错。比如可能在表单的校验逻辑或者某些方法中引用了尚未渲染的表单元素,导致调用getBoundingClientRect时出错。 接下来,我需要考虑解决方案。常见的做法是使用v-show代替v-if,因为v-show只是通过CSS的display属性来控制显示,组件始终会被渲染,这样相关的DOM元素一直存在,避免了访问null的情况。不过,用户可能需要动态创建或销毁表单,这时候用v-show可能不太合适,尤其是当表单结构复杂时,可能会有性能问题。如果必须使用v-if,可能需要确保在表单渲染完成后再进行相关操作,比如在nextTick中调用方法,或者在表单显示之后才触发校验等操作。 另外,检查代码中是否有在表单未渲染时就调用其方法的地方,比如在mounted钩子中直接进行校验,而此时表单可能还没渲染。需要调整这些调用的时机,确保在表单存在后再执行。 可能还需要确认版本问题,有时候Element UI的某些版本可能存在类似的bug,升级到最新版本可能会解决。同时,检查表单的ref是否正确设置,是否有拼写错误,导致通过ref访问表单实例时出错。 总结下来,解决方案可能有以下几点:1. 替换v-if为v-show;2. 确保在表单渲染后执行相关操作,使用nextTick;3. 检查代码中访问表单的时机和条件;4. 更新组件库版本;5. 检查ref是否正确引用。 然后,我需要将这些思路整理成结构清晰的回答,分点说明,并给出示例代码。同时,注意用户提到的报错信息中的getBoundingClientRect,这可能与表单的布局或校验时的DOM操作有关,需要特别强调使用v-show或者确保表单存在后再操作。 最后,生成相关问题,考虑用户可能遇到的类似问题,比如其他条件渲染导致的报错,表单校验问题,或者Element UI的其他常见错误。</think>### 解决方案分析 #### 问题原因 在使用 `el-form` 时,若通过 `v-if` 控制表单的显示/隐藏,当条件为 `false` 时,组件会从 DOM 中完全移除。此时若表单的校验、布局计算等操作被触发(例如通过 `validate` 方法或自动布局调整),会因无法获取 DOM 元素而报错 `Cannot read properties of null (reading 'getBoundingClientRect')`[^1]。 --- ### 解决方案 #### 1. 使用 `v-show` 替代 `v-if` `v-show` 通过 CSS 的 `display: none` 控制显隐,组件始终存在于 DOM 中,避免因元素不存在导致的报错。 ```html <el-form v-show="isFormVisible">...</el-form> ``` #### 2. 确保表单渲染完成后再操作 若必须使用 `v-if`,在表单显示后通过 `this.$nextTick()` 确保 DOM 渲染完成再触发相关操作: ```javascript this.isFormVisible = true; this.$nextTick(() => { this.$refs.form.validate(); // 确保表单已渲染 }); ``` #### 3. 检查表单校验触发时机 避免在表单未渲染时调用校验方法。例如,在 `mounted` 钩子中校验前需先判断表单是否存在: ```javascript mounted() { if (this.isFormVisible) { this.$refs.form.validate(); } } ``` --- ### 示例代码 ```html <template> <div> <button @click="toggleForm">切换表单</button> <el-form v-if="isFormVisible" ref="myForm" :model="formData" @submit.native.prevent > <el-form-item label="姓名" prop="name"> <el-input v-model="formData.name"></el-input> </el-form-item> <el-button type="primary" @click="submitForm">提交</el-button> </el-form> </div> </template> <script> export default { data() { return { isFormVisible: false, formData: { name: '' } }; }, methods: { toggleForm() { this.isFormVisible = !this.isFormVisible; if (this.isFormVisible) { this.$nextTick(() => { this.$refs.myForm.clearValidate(); // 确保表单已渲染 }); } }, submitForm() { this.$refs.myForm.validate(valid => { if (valid) { /* 提交逻辑 */ } }); } } }; </script> ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值