参照jQuery.ajax改造tangram的baidu.url.jsonToQuery()方法使之支持json嵌套对象的解析
背景:项目里用的tangram1.5.2基础库,原因就不说了。是个整站式Ajax应用,Ajax数据的传输在项目中处于至关重要的地位。
我们前后端交互的数据中包括多层json嵌套的场景,比如:
var data = { list1 : [ 0, 1, 2, 3], list2 : [ { key : 'hello', value : 'world' }, { key : 'img', value : 'src' } ] };
由于Ajax支持的传输方式只能是String,因而必须在请求发出前将json解析成string。tangram中提供的json转义方法可用的就只有baidu.url.jsonToQuery()了。其源码如下:
/** * 将json对象解析成query字符串 * @name baidu.url.jsonToQuery * @function * @grammar baidu.url.jsonToQuery(json[, replacer]) * @param {Object} json 需要解析的json对象 * @param {Function=} replacer_opt 对值进行特殊处理的函数,function (value, key) * @see baidu.url.queryToJson,baidu.url.getQueryValue * * @return {string} - 解析结果字符串,其中值将被URI编码,{a:'&1 '} ==> "a=%261%20"。 */ baidu.url.jsonToQuery = function (json, replacer_opt) { var result = [], itemLen, replacer = replacer_opt || function (value) { return baidu.url.escapeSymbol(value); }; baidu.object.each(json, function(item, key){ // 这里只考虑item为数组、字符串、数字类型,不考虑嵌套的object if (baidu.lang.isArray(item)) { itemLen = item.length; // value的值需要encodeURIComponent转义吗? // FIXED 优化了escapeSymbol函数 while (itemLen--) { result.push(key + '=' + replacer(item[itemLen], key)); } } else { result.push(key + '=' + replacer(item, key)); } }); return result.join('&'); };
用这方法baidu.url.jsonToQuery( data )的结果是: list1=3&list1=2&list1=1&list1=0&list2=[object%20Object]&list2=[object%20Object]
完全不是期待中的结果。
通过查看源码发现,这货不支持多层嵌套的Object。没办法,只能自己动手将它改装了。
jQuery Ajax中序列化ajax传输数据的源码:
jQuery.extend({ /* ..... other methods */ // Serialize an array of form elements or a set of // key/values into a query string param: function( a, traditional ) { var s = [], add = function( key, value ) { // If value is a function, invoke it and return its value value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value ); s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value ); }; // Set traditional to true for jQuery <= 1.3.2 behavior. if ( traditional === undefined ) { traditional = jQuery.ajaxSettings.traditional; } // If an array was passed in, assume that it is an array of form elements. if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { // Serialize the form elements jQuery.each( a, function() { add( this.name, this.value ); }); } else { // If traditional, encode the "old" way (the way 1.3.2 or older // did it), otherwise encode params recursively. for ( var prefix in a ) { buildParams( prefix, a[ prefix ], traditional, add ); } } // Return the resulting serialization return s.join( "&" ).replace( r20, "+" ); } }); function buildParams( prefix, obj, traditional, add ) { if ( jQuery.isArray( obj ) ) { // Serialize array item. jQuery.each( obj, function( i, v ) { if ( traditional || rbracket.test( prefix ) ) { // Treat each array item as a scalar. add( prefix, v ); } else { // If array item is non-scalar (array or object), encode its // numeric index to resolve deserialization ambiguity issues. // Note that rack (as of 1.0.0) can't currently deserialize // nested arrays properly, and attempting to do so may cause // a server error. Possible fixes are to modify rack's // deserialization algorithm or to provide an option or flag // to force array serialization to be shallow. buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add ); } }); } else if ( !traditional && jQuery.type( obj ) === "object" ) { // Serialize object item. for ( var name in obj ) { buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); } } else { // Serialize scalar item. add( prefix, obj ); } }
不得不说JQ的数据容错、完备性做的真心好。
改装后:
/** * 将json对象解析成query字符串 * @name baidu.url.jsonToQuery * @function * @grammar baidu.url.jsonToQuery(json[, replacer]) * @param {Object} json 需要解析的json对象 * @param {Function=} replacer_opt 对值进行特殊处理的函数,function (value, key) * @see baidu.url.queryToJson,baidu.url.getQueryValue * * @modify 加入嵌套的json对象的解析方法(参照JQ实现) * * @return {string} - 解析结果字符串,其中值将被URI编码,{a:'&1 '} ==> "a=%261%20"。 */ baidu.url.jsonToQuery = function (json, replacer_opt) { var result = [], itemLen, replacer = replacer_opt || function (value) { return baidu.url.escapeSymbol(value); }, add = function( key, value ) { // If value is a function, invoke it and return its value value = baidu.lang.isFunction( value ) ? value() : ( value == null ? "" : value ); result[ result.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value ); }; function buildParams( prefix, obj, add ) { // 考虑嵌套的object if ( baidu.lang.isArray(obj) ) { itemLen = obj.length; // value的值需要encodeURIComponent转义吗? // FIXED 优化了escapeSymbol函数 baidu.array.each( obj, function( item, i ) { buildParams( prefix + "[" + ( typeof item === "object" ? i : "" ) + "]", item, add ); } ); } else if ( typeof obj === "object" ) { for ( var name in obj ) { buildParams( prefix + "[" + name + "]", obj[ name ], add ); } } else { // Serialize scalar item. add( prefix, obj ); } } baidu.object.each(json, function(item, key){ // 增加嵌套的object的计算 buildParams( key, item, add ); }); return s.join('&'); };
再次用baidu.url.jsonToQuery(data)试试:
list1%5B%5D=0&list1%5B%5D=1&list1%5B%5D=2&list1%5B%5D=3&list2%5B0%5D%5Bkey%5D=hello&list2%5B0%5D%5Bvalue%5D=world&list2%5B1%5D%5Bkey%5D=img&list2%5B1%5D%5Bvalue%5D=src
嗯,这才是我们想要的。搞定~ ^ ^
喜欢的生活是婴儿一样的生活。吃东西,喝牛奶,被人抱着被人迁就,不用担心体重,不用工作,可以随时随地大哭和大笑,没有忧伤,没有牵挂。

浙公网安备 33010602011771号