如何解决 vue-class-setup 与 Element 自定义校验规则不兼容?

前提

在社区看到了一篇 使用 vue-class-setup 编写 class 风格组合式API,支持Vue2和Vue3挺有意思的,于是写了几个 demo,现在结合element plus 自定义校验规则写的demo出现问题。

问题描述

主要在 rules 的时候自定义验证器 validator 传入方法出现问题,具体表现为传入验证器的方法从里面是调用不到类的方法的。

如何解决 vue-class-setup 与 Element 自定义校验规则不兼容?

代码

主要在 public validatePass(rule: any, value: any, callback: any) 这里面调用的类方法都是 undefined 的

<script lang="ts">
import { Setup, Context } from 'vue-class-setup';
import type { FormInstance } from 'element-plus'

interface Wings {
  fly(): void;
}

@Setup
class FormClass extends Context implements Wings {
  fly(): void {
    console.log("fly");
  }

  public ruleFormRef: FormInstance = undefined

  setRuleFormRef(ruleFormRef: FormInstance) {
    this.ruleFormRef = ruleFormRef
  }

  logRuleFormRef(){
    console.log("logRuleFormRef ", this.ruleForm);
  }

  public ruleForm = {
    pass: '',
    checkPass: '',
    age: '',
  };

  public rules = {
    pass: [{ validator: this.validatePass, trigger: 'blur' }],
    checkPass: [{ validator: this.validatePass2, trigger: 'blur' }],
    age: [{ validator: this.checkAge, trigger: 'blur' }],
  }

  setRules(rules:any){
    this.rules = rules
  }

  public checkAge(rule: any, value: any, callback: any) {
    console.log("age rule value", value);

    if (!value) {
      return callback(new Error('Please input the age'))
    }
    setTimeout(() => {
      if (!Number.isInteger(value)) {
        callback(new Error('Please input digits'))
      } else {
        if (value < 18) {
          callback(new Error('Age must be greater than 18'))
        } else {
          callback()
        }
      }
    }, 1000)
  }

  public validatePass(rule: any, value: any, callback: any) {
    // this.logRuleFormRef()
    console.log("this.ruleForm validatePass ", this.ruleForm, value);
    if (value === '') {
      callback(new Error('Please input the password'))
    } else {
      if (this.ruleForm.checkPass !== '') {
        if (!this.ruleFormRef) return
        this.ruleFormRef.validateField('checkPass', () => null)
      }
      callback()
    }
  }

  public validatePass2(rule: any, value: any, callback: any) {
    if (value === '') {
      callback(new Error('Please input the password again'))
    } else if (value !== this.ruleForm.pass) {
      callback(new Error("Two inputs don't match!"))
    } else {
      callback()
    }
  }

  public submitForm(formEl: FormInstance | undefined) {
    console.log("this.ruleForm ", this.ruleForm);

    if (!formEl) return
    formEl.validate((valid) => {
      if (valid) {
        console.log('submit!')
      } else {
        console.log('error submit!')
        return false
      }
    })
  }

  public resetForm(formEl: FormInstance | undefined) {
    if (!formEl) return
    formEl.resetFields()
  }
}

export default defineComponent({
  ...FormClass.inject(),
});
</script>

<script setup lang="ts">
import { defineComponent, defineExpose } from 'vue';
</script>


<template>
  <div class="">
    <el-form ref="ruleFormRef" :model="ruleForm" status-icon :rules="rules" label-width="120px"
      class="demo-ruleForm">
      <el-form-item label="Password" prop="pass">
        <el-input v-model="ruleForm.pass" type="password" autocomplete="off" />
      </el-form-item>
      <el-form-item label="Confirm" prop="checkPass">
        <el-input v-model="ruleForm.checkPass" type="password" autocomplete="off" />
      </el-form-item>
      <el-form-item label="Age" prop="age">
        <el-input v-model.number="ruleForm.age" />
      </el-form-item>
      <el-form-item>
        <el-button type="primary" @click="submitForm(ruleFormRef)">Submit</el-button>
        <el-button @click="resetForm(ruleFormRef)">Reset</el-button>
      </el-form-item>
    </el-form>
  </div>
</template>


<style lang="scss" scoped>

</style>

结语

有其他小 bug 也可以解决,产生这个原因感觉应该是类和全局方法产生了不一致。

讨论数量: 11

有demo 链接吗?我看看

2周前 评论
wozailu (楼主) 2周前
狼族小狈 (作者) 2周前
wozailu (楼主) 2周前
狼族小狈 (作者) 2周前
狼族小狈 (作者) 2周前

好的,我看看。

2周前 评论

还有第三个方案:手动绑定一下this的指向

2周前 评论
wozailu (楼主) 2周前
狼族小狈 (作者) 2周前
<script lang="ts">
import { Setup, Context } from 'vue-class-setup';
import type { FormInstance } from 'element-plus'

interface Wings {
  fly(): void;
}

@Setup
class FormClass extends Context implements Wings {
  fly(): void {
    console.log("fly");
  }

  public ruleFormRef: FormInstance = undefined

  setRuleFormRef(ruleFormRef: FormInstance) {
    this.ruleFormRef = ruleFormRef
  }

  logRuleFormRef(){
    console.log("logRuleFormRef ", this.ruleForm);
  }

  public ruleForm = {
    pass: '',
    checkPass: '',
    age: '',
  };

  public rules = {
    pass: [{ validator: this.validatePass.bind(this), trigger: 'blur' }],
    checkPass: [{ validator: this.validatePass2.bind(this), trigger: 'blur' }],
    age: [{ validator: this.checkAge.bind(this), trigger: 'blur' }],
  }

  setRules(rules:any){
    this.rules = rules
  }

  public checkAge(rule: any, value: any, callback: any) {
    console.log("age rule value", value);

    if (!value) {
      return callback(new Error('Please input the age'))
    }
    setTimeout(() => {
      if (!Number.isInteger(value)) {
        callback(new Error('Please input digits'))
      } else {
        if (value < 18) {
          callback(new Error('Age must be greater than 18'))
        } else {
          callback()
        }
      }
    }, 1000)
  }

  public validatePass(rule: any, value: any, callback: any) {
    // this.logRuleFormRef()
    console.log("this.ruleForm validatePass ", this.ruleForm, value);
    if (value === '') {
      callback(new Error('Please input the password'))
    } else {
      if (this.ruleForm.checkPass !== '') {
        if (!this.ruleFormRef) return
        this.ruleFormRef.validateField('checkPass', () => null)
      }
      callback()
    }
  }

  public validatePass2(rule: any, value: any, callback: any) {
    if (value === '') {
      callback(new Error('Please input the password again'))
    } else if (value !== this.ruleForm.pass) {
      callback(new Error("Two inputs don't match!"))
    } else {
      callback()
    }
  }

  public submitForm(formEl: FormInstance | undefined) {
    console.log("this.ruleForm ", this.ruleForm);

    if (!formEl) return
    formEl.validate((valid) => {
      if (valid) {
        console.log('submit!')
      } else {
        console.log('error submit!')
        return false
      }
    })
  }

  public resetForm(formEl: FormInstance | undefined) {
    if (!formEl) return
    formEl.resetFields()
  }
}

export default defineComponent({
  ...FormClass.inject(),
});
</script>

<script setup lang="ts">
import { defineComponent, defineExpose } from 'vue';
</script>


<template>
  <div  style="height: 600px; width: 600px;">
    <el-form ref="ruleFormRef" :model="ruleForm" status-icon :rules="rules" label-width="120px"
      class="demo-ruleForm">
      <el-form-item label="Password" prop="pass">
        <el-input v-model="ruleForm.pass" type="password" autocomplete="off" />
      </el-form-item>
      <el-form-item label="Confirm" prop="checkPass">
        <el-input v-model="ruleForm.checkPass" type="password" autocomplete="off" />
      </el-form-item>
      <el-form-item label="Age" prop="age">
        <el-input v-model.number="ruleForm.age" />
      </el-form-item>
      <el-form-item>
        <el-button type="primary" @click="submitForm(ruleFormRef)">Submit</el-button>
        <el-button @click="resetForm(ruleFormRef)">Reset</el-button>
      </el-form-item>
    </el-form>
  </div>
</template>


<style lang="scss" scoped>
</style>
2周前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!