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幾乎可以把調用處的任何數據傳入。

以上僅一家之言,當然如果你有更爲簡潔巧妙的封裝方案,歡迎指出!

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