一、背景
公司的老項目前端還是用的jquery,也沒有條件引入vue,所以對于一個實體對象的取值和賦值還是很麻煩的:
例如:

image.png
所以想擴展一下
$.val()函數
二、目標
在html元素上使用name結構化數據實體,
然后用val獲取整個實體,可以正確處理子對象和數組對象以及多選select。
例如:

三、修改方案
找到$().val的源碼;
會用jquery的同學都很清楚,val有2個邏輯,不帶參是get,帶參是set;
看源碼,有一個JQuery.valHooks 對象,如果當前元素可以匹配到則會直接調用valHooks中定義好的get或set方法;
所以只要在這里加入我們定義好的元素和處理函數就可以了

四、改造Get
先來改造Get

將希望處理的元素全部加進去:

五、改造Set
set方法有一個比較有意思的地方,在數組的操作中,每次都要能取出數組中的下一個元素,有點類似C#中的IEnumerator
使用時,需要將數組轉為 Enumerator 再調用 .next() 方法來獲取下一個值;
PS:這里有個特殊情況是 <select multiple>是可以直接用數組賦值的
function Enumerator(array) {
if (array == null) {
return;
}
let index = 0;
this.next = function () {
if (index >= array.length) {
index = 0;
}
return array[index++];
};
this.all = function () {
return array;
};
}
// ...
let val = model[name];
if ($.isArray(val)) {
val = model[name] = new Enumerator(val);
}
if (val instanceof Enumerator) {
if (jq.is("select[multiple]")) {
jq.val(val.all());
} else {
jq.val(val.next());
}
}
但是這樣做會改變model對象中的值,所以需要先將model對象拷貝出來使用
function Copied(value) { Object.assign(this, value); }
// ...
const copied = model instanceof Copied ? value : Copied(value);
完整set代碼
