console
(($) => {
if ($.valHooks.div) {
return;
}
const eleHooks = "div,span,ul,ol,li,table,tr,td,th,tbody,thead,tfoot,a,b,caption,p,pre,label,form,font,i".toLowerCase().split(",").map($.trim);
function Enumerator(array) {
if (array == null) {
return;
}
let index = 0;
this.next = function () {
if (index < array.length) {
return array[index++];
}
};
this.reset = function () {
index = 0;
};
this.all = function () {
return array;
};
this.get = function (index) {
return array[index];
};
}
function Copied(value) { Object.assign(this, value); }
function assign(values) {
const result = {};
for (let value of values) {
for (let key of Object.keys(value)) {
if (key in result) {
if (!$.isArray(result[key])) {
result[key] = [result[key]];
}
result[key] = result[key].concat(value[key]);
} else {
result[key] = value[key];
}
}
}
return result;
}
const handlers = [
{
is(jq) { return jq.is(":checkbox,:radio") },
getValue(jq) { return jq.is(":checked") ? jq.val() : null; },
setValue(jq, value) { jq.val([].concat(value)); }
},
{
is(jq) { return jq.is("select[multiple]") },
getValue(jq) { return [].concat(jq.val()) },
setValue(jq, value) { jq.val([].concat(value)); }
},
{
is(jq) { return jq.is("[multiple]") },
getValue(jq) { return jq.val() },
setValue(jq, value) { jq.val(value); }
},
{
is(jq) { return eleHooks.includes(jq[0].nodeName.toLowerCase()) },
getValue(jq) { return jq.val(); },
setValue(jq, value) { jq.val(value); }
},
{
is(jq) { return jq.is(":input,img") || jq.children().length > 0 },
getValue(jq) { return jq.val(); },
setValue(jq, value) { jq.val(value); }
},
{
is(jq) { return jq.is("[value]"); },
getValue(jq) { return jq.attr("value"); },
setValue(jq, value) { jq.attr("value", value); }
},
{
is(jq) { return true },
getValue(jq) { return jq.text(); },
setValue(jq, value) { (jq.is("[name]")) && jq.text(value); }
},
];
function getValue(jq) {
for (let handler of handlers) {
if (handler.is(jq)) {
return handler.getValue(jq);
}
}
}
function setValue(jq, value) {
if (value == null) {
return;
}
const oldValue = getValue(jq);
for (let handler of handlers) {
if (handler.is(jq) && !equals(oldValue, value)) {
handler.setValue(jq, value);
if (!equals(oldValue, getValue(jq))) {
jq.triggerHandler("change");
}
return;
}
}
}
function equals(value1, value2) {
if (value1 == null || value2 == null) {
return value1 == value2;
}
if ($.isArray(value1) && $.isArray(value2)) {
if (value1.length !== value2.length) {
return false;
}
value1 = value1.sort();
value2 = value2.sort();
for (let i = 0; i < value1.length; i++) {
if (!equals(value1[i], value2[i])) {
return false;
}
}
return true;
}
return value1 == value2;
}
function getName(jq) {
const name = $.trim(jq.attr("name"));
if (!name && jq.is(":input")) {
return $.trim(jq.attr("id"));
}
return name;
}
function isPlainObject(obj) {
try {
return $.isPlainObject(obj);
} catch (e) {
return true;
}
}
const valHook = {
get(ele) {
const jq = $(ele);
const children = jq.children(":not(template)");
if (children.length === 0) {
if (jq.is("[name]")) {
let value = jq.prop("value");
if (value != null) {
return value;
}
value = jq.attr("value");
if (value != null) {
return value;
}
return jq.text();
}
}
const values = children.map(function () {
const jq = $(this);
if (jq.is(":checkbox,:radio,option") && !jq.is(":checked")) {
return null;
}
const name = getName(jq);
if (name) {
return { [name]: getValue(jq) };
}
const val = jq.val();
if ($.isPlainObject(val)) {
return val;
}
return null;
}).toArray().filter(x => x != null);
return assign(values);
},
set(ele, value) {
const jq = $(ele);
const children = jq.children();
if (children.length === 0) {
handlers[handlers.length - 1].setValue(jq, value);
return ele;
}
const copied = value instanceof Copied || !isPlainObject(value) || Object.keys(value).length === 0 ? value : new Copied(value);
return children.each(function () {
const jq = $(this);
const name = getName(jq);
if (!name && eleHooks.includes(this.nodeName.toLowerCase())) {
setValue(jq, copied);
return this;
}
if (copied.hasOwnProperty(name)) {
let val = copied[name];
if ($.isArray(val)) {
val = copied[name] = new Enumerator(val);
}
if (!(val instanceof Enumerator)) {
setValue(jq, val);
} else if (jq.is("select[multiple],:checkbox,:radio")) {
setValue(jq, val.all());
} else {
if (jq.is("[reset]")) {
val.reset();
}
setValue(jq, val.next());
}
}
return this;
});
}
};
$.extend($.valHooks, assign(eleHooks.map(x => ({ [x]: valHook }))));
$.extend($.valHooks, {
img: {
get(ele) {
return ele.src;
},
set(ele, value) {
ele.src = value;
}
}
})
})(jQuery);
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
<div class="container">
<input type="hidden" name="ID" value="" />
<div>
<label>姓名</label><input name="Name" />
</div>
<div>
<label>性别</label>
<label>男<input type="radio" name="Sex" value="男" /></label>
<label>女<input type="radio" name="Sex" value="女" /></label>
</div>
<div>
<label>爱好</label>
<select multiple name="Like">
<option value="唱歌">唱歌</option>
<option value="跳舞">跳舞</option>
<option value="写代码">写代码</option>
</select>
</div>
<div>
<label>标签</label>
<label>80后<input type="checkbox" name="Tags" value="80后" /></label>
<label>码农<input type="checkbox" name="Tags" value="码农" /></label>
<label>富二代<input type="checkbox" name="Tags" value="富二代" /></label>
</div>
<label>账户</label>
<ol>
<li name="Account">
<div>
<label>卡号</label><input name="CardNo" />
</div>
<div>
<label>余额</label><input name="Balance" />
</div>
<div>
<label>关联</label><input multiple name="Links" />
</div>
</li>
<li name="Account">
<div>
<label>卡号</label><input name="CardNo" />
</div>
<div>
<label>余额</label><input name="Balance" />
</div>
<div>
<label>积分</label><input name="Score" />
</div>
</li>
</ol>
<div>
<label>电话1</label><input name="Phone" value="" />
</div>
<div>
<label>电话2</label><input name="Phone" value="" />
</div>
<div>
<label>电话3</label><input name="Phone" value="" />
</div>
<HR />
<button type="button" onclick="setModel()">赋值 $(".container").val({...});</button>
<button type="button" onclick="getModel()">取值 $(".container").val();</button>
<HR />
</div>
<pre>
</pre>
<script>
function setModel() {
$(".container").val({
ID: "1",
Name: "zijian666",
Like: ["唱歌", "写代码"],
Sex: "男",
Tags: ["80后", "码农"],
Account: [
{ CardNo: "0001", Balance: 100, Links: ["x"] },
{ CardNo: "0002", Balance: 123456789, Score: 1 },
{ CardNo: "---" },
],
Phone: ["131", "132"]
});
}
function getModel() {
var model = $(".container").val();
$("pre").text(JSON.stringify(model, null, " "))
}
</script>
</body>
</html>