表单序列化与反序列化JSON对象(基于jQuery)

蓝咒 提交于 2019-12-02 01:01:39

最近根据自身项目的特点写了一个表单序列化与反序列化工具,该工具是基于jQuery的,生成JSON对象。虽然jQuery本身已经实现了相似功能和API($().serialize() 和 $().serializeArray()),但使用起来不是特别方便。以下是我的实现方式:

序列化表单值,结果以key/value形式返回JSON数据。key为表单对象名称(name||id),value为其值。

表单HTML格式约定:

  1. 表单容器:通常是一个form表单(如果不存在就以body为父容器)或div,里面包含输入标签和子容器;

  2. 子容器(也可以没有):必须包括属性fieldset="XXX" div标签,里面包含输入标签和子容器。序列化后将生成以XXX为主键的json对象.如果子容器存在嵌套则以fieldset为主键生成不同分组的json对象。

  3. 输入标签:输入标签为input类型标签(包括:'checkbox','color','date','datetime','datetime-local','email','file','hidden','month','number','password','radio','range','reset','search','submit','tel','text','time ','url','week')。而'button','reset','submit','image'会被过虑掉。

示例HTML页面(下载):

<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Form Serialize & Deserialize</title>
<script src="js/jquery-1.7.2.min.js"></script>
<script src="js/iTsai-webtools.form.js"></script>
</head>
<style type="text/css">
.cls {
	border:2px solid #f00;
}
</style>
<body>
<input type="button" value="Serialize.." onclick="console.log(iTsai.form.serialize($('#frm')));"/>
<input type="button" value="Deserialize.." onclick="console.log(iTsai.form.deserialize($('#frm'),json));"/>
<hr/>
<form id="frm" name="frm" style="border:1px solid #ccc;padding:20px;">
  <input type="button" id="btn1" name="btn" value="btn001">
  <input type="reset" id="reset" name="reset" value="reset">
  <input type="submit" id="submit" name="submit" value="submit">
  <br>
  <br>
  <input type="number" id="number2" name="number" value="10086">
  number <br>
  <input type="checkbox" id="chk_00" name="chk0" value="chk-0"/>
  <input type="checkbox" id="chk_01" name="chk1" value="chk-1" checked/>
  chekckbox <br>
  <input type="radio" id="radio-0" name="radiox" value="0">
  <input type="radio" id="radio-1" name="radiox" value="1" checked>
  <input type="radio" id="radio-2" name="radiox" value="2">
  radio <br>
  <select name="sel">
    <option value="1">1</option>
    <option value="2" selected>2</option>
  </select>
  select <br/>
  <select id="sel-multi" name="multi" multiple="multiple">
    <option value="111">111</option>
    <option value="222" selected="selected">222</option>
    <option value="333" selected="selected">333</option>
    <option value="444">444</option>
  </select>
  select-multiple<br/>
  <div fieldset="basic" class="cls">
    <input type="password" id="pwd" name="pwd" value="123465">
    password <br>
    <input type="text" id="txt" name="txt" value="this is my info">
    text <br>
  </div>
  <input type="color" id="clr-01" name="color" value="#fff"/>
  color <br>
  <input type="date" id="date" name="date" value="2012-12-23"/>
  date <br>
  <input type="datetime" id="dt" name="dt" value="2012-12-23 12:12:12"/>
  datetime <br>
  <input type="datetime-local" id="dtl" name="dtl" value="2012-12-23 12:12:12"/>
  datetime-local <br>
  <input type="time" id="time" name="time" value="12:23:11">
  time <br>
  <input type="week" id="week" name="week" value="Mon.">
  week <br>
  <input type="month" id="month" name="month" value="12">
  month <br>
  <input type="email" id="email" name="email" value="demo@xy.com"/>
  email <br>
  <input type="file" id="file" name="fileurl" value="D:\\txt.txt"/>
  file <br>
  <input type="hidden" id="hide" name="hide" value="_VALUE"/>
  hidden <br>
  <input type="image" id="image" name="image" src="../image/bt_blue.png" value="imag-value">
  image <br>
  <div fieldset="user" class="cls">
    <input type="number" id="number" name="number" value="10016">
    number <br>
    <input type="range" id="range" name="range" min="10" max="110" value="12"/>
    range <br>
    <input type="search" id="sch" name="sch" value="search text.." >
    search <br>
    <input type="tel" id="tel" name="tel" value="023-11112222">
    tel <br>
    <input type="url" id="url" name="url" value="https://www.google.com">
    url <br>
    <textarea id="content" name="cont" rows="3" cols="10">textarea info.</textarea>
  </div>
</form>
<script type="text/javascript">
//测试反序列化示例,序列化后将生成同样数据格式的JSON对象
var json = {
	"image" : "IMAGE -VALUE",
	"hide" : "_VALUE111",
	"fileurl" : "C:txt",
	'number' : 1008655,
	"email" : "123@xy.com",
	"month" : "11",
	"week" : "Sat.",
	"time" : "11:23:11",
	"dtl" : "2011-12-23 12:12:12",
	"dt" : "2011-12-23 12:12:12",
	"date" : "2011-12-23",
	"color" : "#ddd",
	"radiox" : "2",
	"chk1" : true,
	"chk0" : false,
	"basic" : {
		pwd : 'qwert',
		txt : 'yiui'
	},
	"user" : {
		number : 111,
		range : 12131,
		sch : 'sdfsaf',
		tel : '145',
		url : 'http://',
		content : 'content content content...'
	},
	sel : '2',
	multi : [111,444]
};

</script>
</body>
</html>


表单处理工具Javascript代码(下载):

/**
 * iTsai WebTools(Web开发工具集)
 * 
 * @author Chihpeng Tsai(470597142@qq.com)
 * @description 表单处理工具.
 */

(function() {
	if (!window.iTsai)
		iTsai = {};
})();

iTsai.form = {
	toString : function() {
		return 'iTsai.form - 表单处理工具';
	},
	/**
	 * 获取单选框值,如果有表单就在表单内查询,否则在全文查询
	 * 
	 * @param{String}name radio名称
	 * @param{$()} frm jQuery object
	 * @returns
	 */
	getRadioValue : function(name, frm) {
		if (frm && frm.find)
			return frm.find('input[name="' + name + '"]:checked').val();
		return $('input[name="' + name + '"]:checked').val();
	},
	/**
	 * 设置单选框值,如果有表单就在表单内查询,否则在全文查询
	 * 
	 * @param{String}name radio名称
	 * @param{String} value
	 * @param{$()} frm
	 * @returns
	 */
	setRadioValue : function(name, value, frm) {
		if (frm && frm.find)
			return frm
					.find('input[name="' + name + '"][value="' + value + '"]')
					.attr('checked', true);
		return $('input[name="' + name + '"][value="' + value + '"]').attr(
				'checked', true);
	},
	/**
	 * 设置select下拉框的值
	 * 
	 * @param{String} selectId 下拉框id号
	 * @param{String/Number} value 值
	 * @param{$()} form jQuery object
	 * @returns
	 */
	setSelectValue : function(selectId, value, frm) {
		if (frm && frm.find)
			return frm.find('#' + selectId + ' option[value="' + value + '"]')
					.attr('selected', true);
		return $('#' + selectId + ' option[value="' + value + '"]').attr(
				'selected', true);
	},
	/**
	 * 在id区域内执行回车提交数据<br>
	 * 实际处理中应该将提交按键放在id区域外,避免重复提交
	 * 
	 * @param{String} id 被绑定对象的ID号
	 * @param{Function} fn 要选择的函数
	 * @returns {Boolean}
	 */
	bindingEnterKey : function(id, fn) {
		$('#' + id).keydown(function(e) {
			if (e.keyCode == 13) {
				if (fn)
					fn();
			}
		});
	},
	/**
	 * 将输入控件集合序列化成对象<br>
	 * 名称或编号作为键,value属性作为值
	 * 
	 * @param {Array}
	 *            inputs input/select/textarea的对象集合
	 * @return {object} json 对象 {key:value,...}
	 */
	_serializeInputs : function(inputs) {
		var json = {};
		if (!inputs) {
			return json;
		}
		for ( var i = inputs.length - 1; i >= 0; i--) {
			var input = $(inputs[i]);
			var type = input.attr('type');
			if (type) {
				type = type.toLowerCase();
			}
			var tagName = input.get(0).tagName;
			var id = input.attr('id');
			var name = input.attr('name');
			var value = null;

			// 判断输入框是否已经序列化过
			if (input.hasClass('_isSerialized')) {
				continue;
			}

			// input输入标签
			if (tagName == 'INPUT' && type) {
				switch (type) {
				case 'checkbox': {
					value = input.is(':checked');
				}
					break;

				case 'radio': {
					if (input.is(':checked')) {
						value = input.attr('value');
					} else {
						continue;
					}
				}
					break;

				default: {
					value = input.val();
				}
				}
			} else {
				// 非input输入标签,如:select,textarea
				value = input.val();
			}

			json[name || id] = value;
			// 清除序列化标记
			input.removeClass('_isSerialized');
		}
		return json;
	},
	/**
	 * 将值填充到输入标签里面
	 * 
	 * @param{Array} inputs 输入标签集合
	 * @param{String/Number} value 值
	 * @returns {___anonymous188_8285}
	 */
	_deserializeInputs : function(inputs, value) {
		if (!inputs && value == null) {
			return this;
		}

		for ( var i = inputs.length - 1; i >= 0; i--) {
			var input = $(inputs[i]);
			// 判断输入框是否已经序列化过
			if (input.hasClass('_isSerialized')) {
				continue;
			}
			var type = input.attr('type');
			if (type) {
				type = type.toLowerCase();
			}
			if (type) {
				switch (type) {
				case 'checkbox': {
					input.attr('checked', value);
				}
					break;

				case 'radio': {
					input.each(function(i) {
						var thiz = $(this);
						if (thiz.attr('value') == value) {
							thiz.attr('checked', true);
						}
					});
				}
					break;

				default: {
					input.val(value);
				}
				}
			} else {
				input.val(value);
			}

			input.addClass('_isSerialized');
		}

		return this;
	},
	/**
	 * 在分组中查找 fieldset (如:fieldset="user")开头的数据域<br>
	 * 
	 * @param {Array}
	 *            groups 输入框分组容器集合
	 * @return {Object} json 对象 {key:value,...}
	 */
	_serializeGroups : function(groups) {
		var json = {};
		if (!groups) {
			return json;
		}

		for ( var i = groups.length - 1; i >= 0; i--) {
			var group = $(groups[i]);
			var key = group.attr('fieldset');
			if (!key) {
				continue;
			}
			var inputs = group
					.find('input[type!=button][type!=reset][type!=submit],select,textarea');
			json[key] = this._serializeInputs(inputs);
			// 添加序列化标记
			inputs.addClass('_isSerialized');
		}
		return json;
	},
	/**
	 * 序列化表单值,结果以key/value形式返回key为表单对象名称(name||id),value为其值.<br>
	 * HTML格式:<br>
	 * 1).表单容器:通常是一个form表单(如果不存在就以body为父容器),里面包含输入标签和子容器;<br>
	 * 2).子容器(也可以没有):必须包括属性fieldset="XXX" div标签,里面包含输入标签和子容器。<br>
	 * 序列化后将生成以XXX为主键的json对象.如果子容器存在嵌套则以fieldset为主键生成不同分组的json对象.<br>
	 * 3).输入标签:输入标签为input类型标签(包括:'checkbox','color','date','datetime','datetime-local',<br>
	 * 'email','file','hidden','month','number','password','radio','range
	 * ','reset','search','submit',<br>
	 * 'tel','text','time ','url','week').
	 * 而'button','reset','submit','image'会被过虑掉.
	 * 
	 * @param{$()} frm jQuery表单对象
	 * @returns {Object} json对象 最多包含两层结构
	 */
	serialize : function(frm) {
		var json = {};
		frm = frm || $('body');
		if (!frm) {
			return json;
		}

		var groups = frm.find('div[fieldset]');
		var jsonGroup = this._serializeGroups(groups);

		var inputs = frm
				.find('input[type!=button][type!=reset][type!=submit][type!=image],select,textarea');
		var json = this._serializeInputs(inputs);

		for ( var key in jsonGroup) {
			json[key] = jsonGroup[key];
		}
		return json;
	},
	/**
	 * 填充表单内容:将json数据形式数据填充到表单内,只解析单层json结构
	 * 
	 * @param{$()} frm jQuery表单对象(或其它容器标签对象,如:div)
	 * @param{Object} json 序列化好的json数据对象,最多只包含两层嵌套
	 * @returns {Object} iTsai.form 对象
	 */
	deserializeSimple : function(frm, json) {
		frm = frm || $('body');
		if (!frm || !json) {
			return this;
		}

		var _deserializeInputs = this._deserializeInputs;
		for ( var key in json) {
			var value = json[key];
			_deserializeInputs(frm, key, value);
		}
		return this;
	},
	/**
	 * 获取合法的输入标签
	 * 
	 * @param {$()}
	 *            container 标签容器
	 * @returns {[]} inputs jQuery对象数组
	 */
	_filterInputs : function(container) {
		var inputs = $(container
				.find('input[type!=button][type!=reset][type!=submit][type!=image][type!=file],select,textarea'));
		return inputs;
	},
	/**
	 * 查找符合条件的输入标签
	 * 
	 * @param{Array} inputs jQueery输入标签数组
	 * @param{String} key 查询关键字
	 * @returns{Array} input 标签数组
	 */
	_findInputs : function(inputs, key) {
		var input = $(inputs.filter('input[name=' + key + '],input[id=' + key
				+ '],textarea[name=' + key + '],textarea[id=' + key
				+ '],select[name=' + key + '],select[id=' + key + ']'));
		return input;
	},
	/**
	 * 填充表单内容:将json数据形式数据填充到表单内,最多解析两层json结构
	 * 
	 * @param{$()} frm jQuery表单对象(或其它容器标签对象,如:div)
	 * @param{Object} json 序列化好的json数据对象,最多只包含两层嵌套
	 * @returns {Object} iTsai.form 对象
	 */
	deserialize : function(frm, json) {
		frm = frm || $('body');
		if (!frm || !json) {
			return this;
		}

		// 缓存json第一层数据对象
		var objects = {};
		// 缓存json嵌套层数据(第二层),将首先被赋值,以避免覆盖
		var groups = {};

		// 数据分组
		for ( var key in json) {
			var value = json[key];
			if (typeof value == 'object' && !$.isArray(value)) {
				groups[key] = value;
			} else {
				objects[key] = value;
			}
		}

		var _deserializeInputs = this._deserializeInputs;
		var _filterInputs = this._filterInputs;
		var _findInputs = this._findInputs;

		// 填充嵌套层数据
		for ( var key in groups) {
			var json = groups[key];
			var div = frm.find('div[fieldset="' + key + '"]');
			if (!div.length) {
				continue;
			}
			var inputs = _filterInputs(div);
			if (!inputs.length) {
				continue;
			}
			for ( var k in json) {
				var val = json[k];
				var input = _findInputs(inputs, k);
				_deserializeInputs(input, val);
			}
		}

		// 填充第一层数据
		var inputs = _filterInputs(frm);
		for ( var key in objects) {
			var value = objects[key];
			var input = _findInputs(inputs, key);
			_deserializeInputs(input, value);
		}

		inputs.filter('._isSerialized').removeClass('_isSerialized');
		return this;
	}
};

//将iTsai.form.serialize绑定到jQuery对象上,可以直接在jQuery对象上调用。如:$('#fr').frmSerizlize();
//此部分代码也可以删除。
(function ($) {
    $.fn.frmSerialize = function() {
       return iTsai.form.serialize($(this));
    }; 
    $.fn.frmDeSerialize = function(json) {
       return iTsai.form.deserialize($(this), json);
    };  }(jQuery));

$('#_lan').frmSerialize();


工具使用:

  1. 序列化表单:iTsai.form.serialize($('#frm')),生成json对象,如果部分表单对象用<div fieldset="user"> ... </div>,包裹起来,将生成key为user的子对象;

  2. 反序列化表单:iTsai.form.deserialize($('#frm'),json),原理与上面相反。

此工具最大的特点就是可以用 <div fieldset="user"> ... </div> 将表单分成不同的组,使生成的JSON对象层次更清晰。


使用截图:


扩展工具:https://github.com/iiTsai/iTsai-Webtools 是一些个人平常用的JS小工具,有兴趣的朋友可以了解下……

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!