資料物件校驗原理

2023-06-29 18:01:02

表單資料校驗

jquery-validation

The jQuery Validation Plugin provides drop-in validation for your existing forms, while making all kinds of customizations to fit your application really easy.

來自jquery-validation
專案。大概就是提供嵌入式的方式去校驗表單,靈活、便捷。

<form>
    <input required>
</form>
<script src="jquery.js"></script>
<script src="jquery.validate.js"></script>
<script>
    $("form").validate();
</script>

看下使用說明,確實十分方便。但是核心的問題是jq的邏輯基於頁面而非js物件。在vdom的洪流中,這種校驗方式註定需要被進一步剝離出來。

jquery-validation核心邏輯在#L748

check: function( element ) {
	...
	// 1 獲取rules物件 {normalizer: function, f1: p1, f2: p2 ...}
	var rules = $( element ).rules();
	...
	// 2 獲取表單獲取函數
	if ( typeof rules.normalizer === "function" ) {
		normalizer = rules.normalizer; // 2.1 自定義表單獲取函數
	} else if (	typeof this.settings.normalizer === "function" ) {
		normalizer = this.settings.normalizer; // 2.2 通用表單獲取函數
	}
	...
	// 3 獲取表單value
	val = normalizer.call( element, val );
	delete rules.normalizer
	...
	// 4 遍歷rules物件 {f1: p1, f2: p2 ...}
	for ( method in rules ) {
		rule = { method: method, parameters: rules[ method ] };
		result = $.validator.methods[ method ].call( this, val, element, rule.parameters );
	}
}

拆解後就很明顯了,共分成4步。

其中第2步和第3步不是非必須的。

第4步中rules和rule近名反意可以換成兩個詞,這裡的校驗即提供了列表校驗,也提供了自定義校驗,這就存在自定義校驗是可以包括列表校驗的這層關係,列表校驗增加了複雜性但是帶來的收益不大甚至可以被自定義校驗取代。

當然這裡也可以學習到一些物件處理技巧,如delete的操作。

資料物件校驗

近些年虛擬DOM火起來了無論是diff演演算法,還是渲染跨平臺的能力都預示著未來可能是vDOM的世界。

基於表單資料的校驗方式就要被改造成基於表單背後的資料物件的校驗方式。結合上面的分析來實現一個輕量靈活的資料物件校驗器。

首要考量就是業務中的空如何定義,以js為例子。

  • ''是空麼?
  • 0是空麼?
  • false是空麼?
  • undefined是空麼?
  • null是空麼?
  • []是空麼?
  • {}是空麼?

我這裡的結論是''undefinednull屬於空,其他屬於空值。

空值合併運運算元,它是ES2020的一個新特性,它的作用是當一個表示式是undefinednull 時為變數設定一個預設值。空值合併運運算元在左側的值是 null 或 undefined 時會返回問號右邊的表示式。

很方便可以使用(data ?? '') === ''這種方式來判空,而不會受到空值影響,非常巧妙。

function required(data, value) {
	return (data ?? '') === '' ? ((false ^ value) === 0) : true
},

規則校驗要比表單校驗更加簡單,核心程式碼很少,也不涉及任何依賴。

function validate(data, rules) {
	for (const key in data)
		if (!validdy.validators[Object.keys(rules[key])[0]](data[key], Object.values(rules[key])[0]))
			return { ok: false, msg }
	return { ok: true, msg: '' }
},

引數解釋如下。

// data 資料物件
const data = {
	name: '',
	plans: [],
}

// rules 校驗規則
const rules = {
	name: {
		required: true,
		msg: '請填寫姓名',
	},
	plans: {
		lenlimit: {min: 1, max: 10},
		msg: '最少包含一個基礎套餐最多包含十個套餐',
	},
}

// validators['contains'] 定義校驗函數 true為通過
validators['lenlimit'] = (data, value) => validators['lenmin'](data, value.min) && validators['lenmax'](data, value.max)


// validated 校驗結果
const validated = validate(data, rules)
if (!validated.ok) { // 失敗邏輯
	return
}
// 通過邏輯

資料物件校驗原始碼已經開源到validdy,js實現,其他語言有興趣自行了解下。