vue+elementUI项目实现自定义校验规则的传参复用性

对于Vue+elementUI的项目而言,表单校验的复用性是一个值得考虑的问题。虽然elementUI默认提供了一些表单校验规则,比如required确定必填项,但是当面对更加复杂多变的实际业务需求时,往往显得不够用,因此就需要自定义校验函数。我们看一下官方案例中自定义校验函数的实现:

export default {
    data() {
      var checkAge = (rule, value, callback) => {
        if (!value) {
          return callback(new Error('年龄不能为空'));
        }
        setTimeout(() => {
          if (!Number.isInteger(value)) {
            callback(new Error('请输入数字值'));
          } else {
            if (value < 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 validatePass2 = (rule, value, callback) => {
        if (value === '') {
          callback(new Error('请再次输入密码'));
        } else if (value !== this.ruleForm.pass) {
          callback(new Error('两次输入密码不一致!'));
        } else {
          callback();
        }
      };
      return {
        ruleForm: {
          pass: '',
          checkPass: '',
          age: ''
        },
        rules: {
          pass: [
            { validator: validatePass, trigger: 'blur' }
          ],
          checkPass: [
            { validator: validatePass2, trigger: 'blur' }
          ],
          age: [
            { validator: checkAge, trigger: 'blur' }
          ]
        }
      };
    },
    methods: {}
复用性

从以上校验函数中可以看出,校验函数都是放于data中return之外,这仅仅只能应对当前组件的情况。如果其他地方也要使用同样的校验规则,就需要再次写一遍,也就是缺乏复用性。当然,这些不是官方文档的主题,而是需要我们自己实现。

显然,我们需要将校验规则函数抽取到单独的js文件中区,这样在不同的组件中就可以直接引入了。

耦合性

一旦我们单独抽取之后,就会发现第二个问题:

校验函数中有很强的耦合性。

正如以上案例中比如this.ruleForm.passthis.$refs.ruleForm.validateField('checkPass'),这些都是写死的固定值,假设我们别的表单字段不同,那么校验函数就不能使用了,复用性也就无从谈起。

this指向问题

单独抽取还会带来另一个问题,即

this指向改变,不会指向原先的组件。

这个问题不得到解决,就会导致校验函数的功能大大削弱,不能传递参数。

破局:使用bind吧

事实上,当我们使用bind的时候,耦合性和this指向问题都能得到很好的解决。例如:

// 校验确认密码
export function checkRepeatPwd(rule, value, callback) {
  if (value === this) {
    callback();
  } else {
    const error = new Error("两次输入的密码不一致");
    callback(error);
  }
}
// 校验是否勾选多选框
export function checkCheckbox(rule, value, callback) {
  if (value === true) {
    callback();
  } else {
    const error = new Error(this);
    callback(error);
  }
}

在以上校验规则的定义函数中,this使得传递参数成为可能。现在我们看看在组件中的使用:

import { checkRepeatPwd } from "@/config/validator";

export default {
  data() {
    return {
      formData: {
        mobile: "",
        authCode: "",
        password: "",
        repeatPassword: ""
      },
      formRules: {
        mobile: [
          { required: true, message: "请输入手机号码" },
          { validator: checkPhone }
        ],
        authCode: [{ required: true, message: "请输入验证码" }],
        password: [{ required: true, message: "请输入密码" }],
        repeatPassword: [
          { required: true, message: "请再次输入密码" },
          {
            validator: checkRepeatPwd.bind(
              this.formData && this.formData.password
            )
          }
        ]
      }
    };
  }
}

repeatPassword本身和组件耦合度是比较高的,因为需要指定要和哪个字段进行比较,而通过在外面使用bind使得封装的校验规则无需关心具体字段,从而去除了耦合性。

合理设计
  • 合理设计bind绑定值。这是因为一方面我们需要通过bind作为中介,将需要的数据传入校验函数中,即实现参数传递的功能,另一方面校验函数可能需要使用组件this能访问到的数据,因此需要设计bind能够进行兼顾。总的说来这并不是大的问题,通过bind几乎可以把调用处的任何数据传入。

以上仅一家之言,当然如果你有更为简洁巧妙的封装方案,欢迎指出!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章