Quasar 中 validate 校验原理

Posted by Ivens on April 26, 2020

前言

最近在项目中一直在与校验作斗争, 今天中午午饭之前, 把 Quasarvalidate.js 的源码拿出来看了下, 分析一下内部是如何实现的.

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/*
 * Return value
 *   - true (validation succeeded)
 *   - false (validation failed)
 *   - Promise (pending async validation)
 */
validate (val = this.value) {
  //  如果没有设置 rules 属性, 直接返回 true
  if (!this.rules || this.rules.length === 0) {
    return true
  }

  this.validateIndex++

  
  if (this.innerLoading !== true && this.lazyRules !== true) {
    this.isDirty = true
  }

  // 更新错误信息
  const update = (err, msg) => {
    if (this.innerError !== err) {
      this.innerError = err
    }

    const m = msg || void 0
    if (this.innerErrorMessage !== m) {
      this.innerErrorMessage = m
    }

    if (this.innerLoading !== false) {
      this.innerLoading = false
    }
  }

  const promises = []

  // 遍历 rules 数组
  for (let i = 0; i < this.rules.length; i++) {
    const rule = this.rules[i]
    let res
		
    // 如果 rule 是一个 function, 把 watch 中侦听的值作为参数传入, 进行校验
    if (typeof rule === 'function') {
      res = rule(val)
    }
    // 如果 rule 为一个字符串, 并且是在 testPattern 中已经存在的, 则调用 testPattern 中内置的方法进行校验
    else if (typeof rule === 'string' && testPattern[rule] !== void 0) {
      res = testPattern[rule](val)
    }

    // 在 Quasar 中规定, rules 内部校验的格式为: "value => condition || errorMessage"
    // 所以一旦前面的 condition 返回的是 false, 当前的 res 则会被赋值为后面的 errorMessage
    // 而 testPattern 中内置的校验则只会返回 true 或 false
    if (res === false || typeof res === 'string') {
      update(true, res)
      return false
    }
    else if (res !== true && res !== void 0) {
      promises.push(res)
    }
  }

  if (promises.length === 0) {
    update(false)
    return true
  }

  if (this.innerLoading !== true) {
    this.innerLoading = true
  }

  const index = this.validateIndex

  return Promise.all(promises).then(
    res => {
      if (index !== this.validateIndex) {
        return true
      }

      if (res === void 0 || Array.isArray(res) === false || res.length === 0) {
        update(false)
        return true
      }

      const msg = res.find(r => r === false || typeof r === 'string')
      update(msg !== void 0, msg)
      return msg === void 0
    },
    e => {
      if (index === this.validateIndex) {
        console.error(e)
        update(true)
        return false
      }

      return true
    }
  )
}

正文

先看返回值, 不难看出我们使用的 validate() 函数, 返回值有 3 种:

  • true
  • false
  • promise (等待异步验证 => 执行下一轮校验)