最近根据自身项目的特点写了一个表单序列化与反序列化工具,该工具是基于jQuery的,生成JSON对象。虽然jQuery本身已经实现了相似功能和API($().serialize() 和 $().serializeArray()),但使用起来不是特别方便。以下是我的实现方式:
序列化表单值,结果以key/value形式返回JSON数据。key为表单对象名称(name||id),value为其值。
表单容器:通常是一个form表单(如果不存在就以body为父容器)或div,里面包含输入标签和子容器;
子容器(也可以没有):必须包括属性fieldset="XXX" div标签,里面包含输入标签和子容器。序列化后将生成以XXX为主键的json对象.如果子容器存在嵌套则以fieldset为主键生成不同分组的json对象。
输入标签:输入标签为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="[email protected]"/> 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" : "[email protected]", "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([email protected]) * @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();
工具使用:
序列化表单:iTsai.form.serialize($('#frm')),生成json对象,如果部分表单对象用<div fieldset="user"> ... </div>,包裹起来,将生成key为user的子对象;
反序列化表单:iTsai.form.deserialize($('#frm'),json),原理与上面相反。
此工具最大的特点就是可以用 <div fieldset="user"> ... </div> 将表单分成不同的组,使生成的JSON对象层次更清晰。
使用截图:
扩展工具:https://github.com/iiTsai/iTsai-Webtools 是一些个人平常用的JS小工具,有兴趣的朋友可以了解下……