下面是对Jquery几个经常用到的地方进行的增强。
功能是参考百度七巧板JS框架来完成的。
一、页面属性
$.page.getHeight():获取页面高度
$.page.getWidth():获取页面宽度
$.page.createStyleSheet(options):在页面中创建样式表对象
$.page.getScrollTop():获取纵向滚动量
$.page.getScrollLeft():获取横向滚动量
$.page.getViewHeight():获取页面视觉区域高度
$.page.getViewWidth():获取页面视觉区域宽度
$.page.getMousePosition(element):获得页面里的目前鼠标所在的坐标
$.page.getPosition(element):获取目标元素相对于整个文档左上角的位置
$.page.lazyLoadImage(options):延迟加载图片. 默认只加载可见高度以上的图片, 随着窗口滚动加载剩余图片.注意: 仅支持垂直方向.
$.page.loadCssFile(path):动态在页面上加载一个外部css文件
$.page.loadJsFile(path):动态在页面上加载一个外部js文件
$.page.load(resources, options, ignoreAllLoaded):加载一组资源,支持多种格式资源的串/并行加载,支持每个文件有单独回调函数。
二、浏览器判断
$.browser.ie
$.browser.firefox
$.browser.chrome
$.browser.isGecko
$.browser.isWebkit
$.browser.isStrict
$.browser.opera
$.browser.safari
三、平台判断
$.platform.isAndroid
$.platform.isIpad
$.platform.isIphone
$.platform.isMacintosh
$.platform.isWindows
$.platform.isX11
四、字符串处理
$.string.decodeHTML(source):对目标字符串进行html解码
$.string.encodeHTML(source):对目标字符串进行html编码
$.string.stripTags(source):去掉字符串中的html标签
$.string.escapeReg(source):将目标字符串中可能会影响正则表达式构造的字符串进行转义。
$.string.trim(source):删除目标字符串两端的空白字符
五、类型
$.lang.guid():返回一个当前页面的唯一标识字符串。
$.lang.isFunction(source):判断目标参数是否为function或Function实例
$.lang.isElement(source):判断目标参数是否为Element对象
$.lang.isArray(source):判断目标参数是否Array对象
六、数组
$.array.indexOf(source, match, fromIndex):查询数组中指定元素的索引位置
$.array.contains(source, obj):判断一个数组中是否包含给定元素
$.array.empty(source):清空一个数组
$.array.lastIndexOf(source, match, fromIndex):从后往前,查询数组中指定元素的索引位置
$.array.map(source, iterator, thisObject):遍历数组中所有元素,将每一个元素应用方法进行转换,并返回转换后的新数组。
$.array.reduce(source, iterator, initializer):遍历数组中所有元素,将每一个元素应用方法进行合并,并返回合并后的结果。
$.array.remove(source, match):移除数组中的项
$.array.removeAt(source, index):移除数组中的项
$.array.unique(source, compareFn):过滤数组中的相同项。如果两个元素相同,会删除后一个元素。
七、cookie
$.cookie.getRaw(key):获取cookie的值,不对值进行解码
$.cookie.setRaw(key, value, options):设置cookie的值,不对值进行编码
$.cookie.remove(key, options):删除cookie的值
$.cookie.get(key):获取cookie的值,用decodeURIComponent进行解码
$.cookie.set(key, value, options):设置cookie的值,用encodeURIComponent进行编码
八、整数
$.number.comma(source, length):为目标数字添加逗号分隔
$.number.randomInt(min, max):生成随机整数,范围是[min, max]
$.number.pad(source, length):对目标数字进行0补齐处理
九、日志
$.sio.log(url):通过请求一个图片的方式令服务器存储一条日志,常用于记录用户点击位置,进行分析统计
十、URL
$.url.escapeSymbol(source):对字符串进行%#&+=以及和s匹配的所有字符进行url转义
$.url.getQueryValue(url, key):根据参数名从目标URL中获取参数值
$.url.jsonToQuery(json, replacer_opt):将json对象解析成query字符串
$.url.queryToJson(url):解析目标URL中的参数成json对象
1 ;(function($){ 2 $.extend({ 3 hasClass:function(targetClassName){ 4 var className = $(this).attr("class"); 5 var classArray = className.split(" "); 6 if(className && classArray.length == 0){ 7 if(targetClassName == className) return true; 8 }else if(className && classArray.length > 0){ 9 for(var i=0; i<=classArray.length-1; i++){ 10 if(classArray[i] == targetClassName) return true; 11 } 12 } 13 14 return false; 15 }, 16 17 getDocument:function (element) { 18 return $.lang.isElement(element) ? element : element.ownerDocument || element.document; 19 } 20 }); 21 })(jQuery); 22 23 ;(function($){ 24 $.lang = $.lang || {}; 25 26 $.lang.isFunction = function (source) { 27 // chrome下,'function' == typeof /a/ 为true. 28 return '[object Function]' == Object.prototype.toString.call(source); 29 }; 30 31 $.lang.isString = function (source) { 32 return '[object String]' == Object.prototype.toString.call(source); 33 }; 34 })(jQuery); 35 36 ;(function($){ 37 38 $.page = $.page || {}; 39 $.page.xy = {x:0, y:0};//当前鼠标坐标 40 41 $.page.getHeight = $.page.getHeight || function(){ 42 var doc = document, 43 body = doc.body, 44 html = doc.documentElement, 45 client = doc.compatMode == 'BackCompat' ? body : doc.documentElement; 46 47 return Math.max(html.scrollHeight, body.scrollHeight, client.clientHeight); 48 }; 49 50 $.page.getWidth = $.page.getWidth || function () { 51 var doc = document, 52 body = doc.body, 53 html = doc.documentElement, 54 client = doc.compatMode == 'BackCompat' ? body : doc.documentElement; 55 56 return Math.max(html.scrollWidth, body.scrollWidth, client.clientWidth); 57 }; 58 59 $.page.createStyleSheet = $.page.createStyleSheet || function(options){ 60 var op = options || {}, 61 doc = op.document || document, 62 s; 63 64 if ($.browser.ie) { 65 //修复ie下会请求一个undefined的bug berg 2010/08/27 66 if(!op.url) 67 op.url = ""; 68 return doc.createStyleSheet(op.url, op.index); 69 } else { 70 s = "<style type='text/css'></style>"; 71 op.url && (s="<link type='text/css' rel='stylesheet' href='"+op.url+"'/>"); 72 $("HEAD:eq(0)").after(s); 73 } 74 }; 75 76 $.page.getScrollTop = $.page.getScrollTop || function(){ 77 var d = document; 78 return window.pageYOffset || d.documentElement.scrollTop || d.body.scrollTop; 79 }; 80 81 $.page.getScrollLeft= $.page.getScrollLeft || function () { 82 var d = document; 83 return window.pageXOffset || d.documentElement.scrollLeft || d.body.scrollLeft; 84 }; 85 86 $.page.getViewHeight = $.page.getViewHeight || function () { 87 var doc = document, 88 client = doc.compatMode == 'BackCompat' ? doc.body : doc.documentElement; 89 90 return client.clientHeight; 91 }; 92 93 $.page.getViewWidth = function () { 94 var doc = document, 95 client = doc.compatMode == 'BackCompat' ? doc.body : doc.documentElement; 96 97 return client.clientWidth; 98 }; 99 100 $(document).bind("mousemove", function(e){ 101 e = window.event || e; 102 $.page.xy.x = e.clientX; 103 $.page.xy.y = e.clientY; 104 //console.log(e.clientX+","+e.clientY); 105 }); 106 107 $.page.getMousePosition = $.page.getMousePosition || function(){ 108 return { 109 x : $.page.getScrollLeft() + $.page.xy.x, 110 y : $.page.getScrollTop() + $.page.xy.y 111 }; 112 }; 113 114 /** 115 * 获取目标元素相对于整个文档左上角的位置 116 * @grammar $.dom.getPosition(element) 117 * @param {HTMLElement|string} element 目标元素或目标元素的id 118 * 119 * @returns {Object} 目标元素的位置,键值为top和left的Object。 120 */ 121 $.page.getPosition = function (element) { 122 var doc = $.getDocument(element), 123 browser = $.browser 124 // Gecko 1.9版本以下用getBoxObjectFor计算位置 125 // 但是某些情况下是有bug的 126 // 对于这些有bug的情况 127 // 使用递归查找的方式 128 BUGGY_GECKO_BOX_OBJECT = browser.isGecko > 0 && 129 doc.getBoxObjectFor && 130 $(element).css('position') == 'absolute' && 131 (element.style.top === '' || element.style.left === ''), 132 pos = {"left":0,"top":0}, 133 viewport = (browser.ie && !browser.isStrict) ? doc.body : doc.documentElement, 134 parent; 135 var box; 136 137 if(element == viewport){ 138 return pos; 139 } 140 141 if(element.getBoundingClientRect){ // IE and Gecko 1.9+ 142 //当HTML或者BODY有border width时, 原生的getBoundingClientRect返回值是不符合预期的 143 //考虑到通常情况下 HTML和BODY的border只会设成0px,所以忽略该问题. 144 doc = document; 145 box = element.getBoundingClientRect(); 146 147 pos.left = Math.floor(box.left) + Math.max(doc.documentElement.scrollLeft, doc.body.scrollLeft); 148 pos.top = Math.floor(box.top) + Math.max(doc.documentElement.scrollTop, doc.body.scrollTop); 149 150 // IE会给HTML元素添加一个border,默认是medium(2px) 151 // 但是在IE 6 7 的怪异模式下,可以被html { border: 0; } 这条css规则覆盖 152 // 在IE7的标准模式下,border永远是2px,这个值通过clientLeft 和 clientTop取得 153 // 但是。。。在IE 6 7的怪异模式,如果用户使用css覆盖了默认的medium 154 // clientTop和clientLeft不会更新 155 pos.left -= doc.documentElement.clientLeft; 156 pos.top -= doc.documentElement.clientTop; 157 158 var htmlDom = doc.body, 159 // 在这里,不使用element.style.borderLeftWidth,只有computedStyle是可信的 160 htmlBorderLeftWidth = parseInt($(htmlDom).css('borderLeftWidth')), 161 htmlBorderTopWidth = parseInt($(htmlDom).css('borderTopWidth')); 162 if(browser.ie && !browser.isStrict){ 163 pos.left -= isNaN(htmlBorderLeftWidth) ? 2 : htmlBorderLeftWidth; 164 pos.top -= isNaN(htmlBorderTopWidth) ? 2 : htmlBorderTopWidth; 165 } 166 /* 167 * 因为firefox 3.6和4.0在特定页面下(场景待补充)都会出现1px偏移,所以暂时移除该逻辑分支 168 * 如果 2.0版本时firefox仍存在问题,该逻辑分支将彻底移除. by rocy 2011-01-20 169 } else if (doc.getBoxObjectFor && !BUGGY_GECKO_BOX_OBJECT){ // gecko 1.9- 170 171 // 1.9以下的Gecko,会忽略ancestors的scroll值 172 // https://bugzilla.mozilla.org/show_bug.cgi?id=328881 and 173 // https://bugzilla.mozilla.org/show_bug.cgi?id=330619 174 175 box = doc.getBoxObjectFor(element); 176 var vpBox = doc.getBoxObjectFor(viewport); 177 pos.left = box.screenX - vpBox.screenX; 178 pos.top = box.screenY - vpBox.screenY; 179 */ 180 } else { // safari/opera/firefox 181 parent = element; 182 183 do { 184 pos.left += parent.offsetLeft; 185 pos.top += parent.offsetTop; 186 // safari里面,如果遍历到了一个fixed的元素,后面的offset都不准了 187 if (browser.isWebkit > 0 && $(parent).css('position') == 'fixed') { 188 pos.left += doc.body.scrollLeft; 189 pos.top += doc.body.scrollTop; 190 break; 191 } 192 193 parent = parent.offsetParent; 194 } while (parent && parent != element); 195 196 // 对body offsetTop的修正 197 if(browser.opera > 0 || (browser.isWebkit > 0 && $(parent).css('position') == 'absolute')){ 198 pos.top -= doc.body.offsetTop; 199 } 200 201 // 计算除了body的scroll 202 parent = element.offsetParent; 203 while (parent && parent != doc.body) { 204 pos.left -= parent.scrollLeft; 205 // see https://bugs.opera.com/show_bug.cgi?id=249965 206 // if (!b.opera || parent.tagName != 'TR') { 207 if (!browser.opera || parent.tagName != 'TR') { 208 pos.top -= parent.scrollTop; 209 } 210 parent = parent.offsetParent; 211 } 212 } 213 214 return pos; 215 }; 216 217 /** 218 * 延迟加载图片. 默认只加载可见高度以上的图片, 随着窗口滚动加载剩余图片.注意: 仅支持垂直方向. 219 * @grammar $.page.lazyLoadImage([options]) 220 * @param {Object} options 221 * @param {String} [options.className] 延迟加载的IMG的className,如果不传入该值将延迟加载所有IMG. 222 * @param {Number} [options.preloadHeight] 预加载的高度, 可见窗口下该高度内的图片将被加载. 223 * @param {String} [options.placeHolder] 占位图url. 224 * @param {Function} [options.onlazyload] 延迟加载回调函数,在实际加载时触发. 225 */ 226 $.page.lazyLoadImage = function(options) { 227 options = options || {}; 228 options.preloadHeight = options.preloadHeight || 0; 229 230 $(document).ready(function() { 231 var imgs = document.getElementsByTagName('IMG'), 232 targets = imgs, 233 len = imgs.length, 234 i = 0, 235 viewOffset = getLoadOffset(), 236 srcAttr = 'data-tangram-ori-src', 237 target; 238 //避免循环中每次都判断className 239 if (options.className) { 240 targets = []; 241 for (; i < len; ++i) { 242 if ($(imgs[i]).hasClass(options.className)) { 243 targets.push(imgs[i]); 244 } 245 } 246 } 247 //计算需要加载图片的页面高度 248 function getLoadOffset() { 249 return $.page.getScrollTop() + $.page.getViewHeight() + options.preloadHeight; 250 } 251 //加载可视图片 252 for (i = 0, len = targets.length; i < len; ++i) { 253 target = targets[i]; 254 if ($.page.getPosition(target).top > viewOffset) { 255 target.setAttribute(srcAttr, target.src); 256 options.placeHolder ? target.src = options.placeHolder : target.removeAttribute('src'); 257 } 258 } 259 //处理延迟加载 260 var loadNeeded = function() { 261 var viewOffset = getLoadOffset(), 262 imgSrc, 263 finished = true, 264 i = 0, 265 len = targets.length; 266 for (; i < len; ++i) { 267 target = targets[i]; 268 imgSrc = target.getAttribute(srcAttr); 269 imgSrc && (finished = false); 270 if ($.page.getPosition(target).top < viewOffset && imgSrc) { 271 target.src = imgSrc; 272 target.removeAttribute(srcAttr); 273 $.lang.isFunction(options.onlazyload) && options.onlazyload(target); 274 } 275 } 276 //当全部图片都已经加载, 去掉事件监听 277 finished && $(window).unbind('scroll', loadNeeded); 278 }; 279 280 $(window).bind('scroll', loadNeeded); 281 }); 282 }; 283 284 /** 285 * 动态在页面上加载一个外部css文件 286 * @grammar $.page.loadCssFile(path) 287 * @param {string} path css文件路径 288 */ 289 $.page.loadCssFile = function (path) { 290 var element = document.createElement("link"); 291 292 element.setAttribute("rel", "stylesheet"); 293 element.setAttribute("type", "text/css"); 294 element.setAttribute("href", path); 295 296 document.getElementsByTagName("head")[0].appendChild(element); 297 }; 298 299 300 /** 301 * 动态在页面上加载一个外部js文件 302 * @grammar $.page.loadJsFile(path) 303 * @param {string} path js文件路径 304 */ 305 $.page.loadJsFile = function (path) { 306 var element = document.createElement('script'); 307 308 element.setAttribute('type', 'text/javascript'); 309 element.setAttribute('src', path); 310 element.setAttribute('defer', 'defer'); 311 312 document.getElementsByTagName("head")[0].appendChild(element); 313 }; 314 315 /** 316 * 317 * 加载一组资源,支持多种格式资源的串/并行加载,支持每个文件有单独回调函数。 318 * 319 * @name $.page.load 320 * @function 321 * @grammar $.page.load(resources[, options]) 322 * 323 * @param {Array} resources 资源描述数组,单个resource含如下属性. 324 * @param {String} resources.url 链接地址. 325 * @param {String} [resources.type] 取值["css","js","html"],默认参考文件后缀. 326 * @param {String} [resources.requestType] 取值["dom","ajax"],默认js和css用dom标签,html用ajax. 327 * @param {Function} resources.onload 当前resource加载完成的回调函数,若requestType为ajax,参数为xhr(可能失效),responseText;若requestType为dom,无参数,执行时this为相应dom标签。. 328 * 329 * @param {Object} [options] 可选参数. 330 * @param {Function} [options.onload] 资源全部加载完成的回调函数,无参数。. 331 * @param {Boolean} [options.parallel] 是否并行加载,默认为false,串行。. 332 * @param {Boolean} [ignoreAllLoaded] 全部加载之后不触发回调事件.主要用于内部实现. 333 * 334 * 335 * @remark 336 * //串行实例 337 * baidu.page.load([ 338 * { url : "http://img.baidu.com/js/tangram-1.3.2.js" }, 339 * {url : "http://xxx.baidu.com/xpath/logicRequire.js", 340 * onload : fnOnRequireLoaded 341 * }, 342 * { url : "http://xxx.baidu.com/xpath/target.js" } 343 * ],{ 344 * onload : fnWhenTargetOK 345 * }); 346 * //并行实例 347 * baidu.page.load([ 348 * { 349 * url : "http://xxx.baidu.com/xpath/template.html", 350 * onload : fnExtractTemplate 351 * }, 352 * { url : "http://xxx.baidu.com/xpath/style.css"}, 353 * { 354 * url : "http://xxx.baidu.com/xpath/import.php?f=baidu.*", 355 * type : "js" 356 * }, 357 * { 358 * url : "http://xxx.baidu.com/xpath/target.js", 359 * }, 360 * { 361 * url : "http://xxx.baidu.com/xpath/jsonData.js", 362 * requestType : "ajax", 363 * onload : fnExtractData 364 * } 365 * ],{ 366 * parallel : true, 367 * onload : fnWhenEverythingIsOK 368 * }); 369 */ 370 $.page.load = function(resources, options, ignoreAllLoaded) { 371 options = options || {}; 372 var self = $.page.load, 373 cache = self._cache = self._cache || {}, 374 loadingCache = self._loadingCache = self._loadingCache || {}, 375 parallel = options.parallel; 376 377 function allLoadedChecker() { 378 for (var i = 0, len = resources.length; i < len; ++i) { 379 if (! cache[resources[i].url]) { 380 setTimeout(arguments.callee, 10); 381 return; 382 } 383 } 384 options.onload(); 385 }; 386 387 function loadByDom(res, callback) { 388 var node, loaded, onready; 389 switch (res.type.toLowerCase()) { 390 case 'css' : 391 node = document.createElement('link'); 392 node.setAttribute('rel', 'stylesheet'); 393 node.setAttribute('type', 'text/css'); 394 break; 395 case 'js' : 396 node = document.createElement('script'); 397 node.setAttribute('type', 'text/javascript'); 398 node.setAttribute('charset', res.charset || self.charset); 399 break; 400 case 'html' : 401 node = document.createElement('iframe'); 402 node.frameBorder = 'none'; 403 break; 404 default : 405 return; 406 } 407 408 // HTML,JS works on all browsers, CSS works only on IE. 409 onready = function() { 410 if (!loaded && (!this.readyState || 411 this.readyState === 'loaded' || 412 this.readyState === 'complete')) { 413 loaded = true; 414 // 防止内存泄露 415 $(node).unbind('load', onready); 416 $(node).unbind('readystatechange', onready); 417 //node.onload = node.onreadystatechange = null; 418 callback.call(window, node); 419 } 420 }; 421 $(node).bind('load', onready); 422 $(node).bind('readystatechange', onready); 423 //CSS has no onload event on firefox and webkit platform, so hack it. 424 if (res.type == 'css') { 425 (function() { 426 //避免重复加载 427 if (loaded) return; 428 try { 429 node.sheet.cssRule; 430 } catch (e) { 431 setTimeout(arguments.callee, 20); 432 return; 433 } 434 loaded = true; 435 callback.call(window, node); 436 })(); 437 } 438 439 node.href = node.src = res.url; 440 document.getElementsByTagName('head')[0].appendChild(node); 441 } 442 443 //兼容第一个参数直接是资源地址. 444 $.lang.isString(resources) && (resources = [{url: resources}]); 445 //避免递归出错,添加容错. 446 if (! (resources && resources.length)) return; 447 448 function loadResources(res) { 449 var url = res.url, 450 shouldContinue = !!parallel, 451 cacheData, 452 callback = function(textOrNode) { 453 //ajax存入responseText,dom存入节点,用于保证onload的正确执行. 454 cache[res.url] = textOrNode; 455 delete loadingCache[res.url]; 456 457 if ($.lang.isFunction(res.onload)) { 458 //若返回false, 则停止接下来的加载. 459 if (false === res.onload.call(window, textOrNode)) { 460 return; 461 } 462 } 463 //串行时递归执行 464 !parallel && self(resources.slice(1), options, true); 465 if ((! ignoreAllLoaded) && $.lang.isFunction(options.onload)) { 466 allLoadedChecker(); 467 } 468 }; 469 //默认用后缀名, 并防止后缀名大写 470 res.type = res.type || url.replace(/^[^?#]+.(css|js|html)(?|#| |$)[^?#]*/i, '$1'); //[bugfix]修改xxx.js?v这种情况下取不到js的问题。 471 //默认html格式用ajax请求,其他都使用dom标签方式请求. 472 res.requestType = res.requestType || (res.type == 'html' ? 'ajax' : 'dom'); 473 474 if (cacheData = cache[res.url]) { 475 callback(cacheData); 476 return shouldContinue; 477 } 478 if (!options.refresh && loadingCache[res.url]) { 479 setTimeout(function() {loadResources(res);}, 10); 480 return shouldContinue; 481 } 482 loadingCache[res.url] = true; 483 if (res.requestType.toLowerCase() == 'dom') { 484 loadByDom(res, callback); 485 }else {//ajax 486 $.getScript(res.url, function(responseText){ 487 callback(responseText); 488 }); 489 } 490 //串行模式,通过callback方法执行后续 491 return shouldContinue; 492 }; 493 494 $.each(resources, function(k, item){ 495 loadResources(item); 496 }); 497 }; 498 //默认编码设置为UTF8 499 $.page.load.charset = 'UTF8'; 500 })(jQuery); 501 502 ;(function($){ 503 /** 504 * 判断浏览器类型 505 */ 506 $.browser = $.browser || {}; 507 508 $.browser.ie = /msie (d+.d+)/i.test(navigator.userAgent) ? (document.documentMode || + RegExp['x241']) : undefined; 509 510 $.browser.firefox = /firefox/(d+.d+)/i.test(navigator.userAgent) ? + RegExp['x241'] : undefined; 511 512 $.browser.chrome = /chrome/(d+.d+)/i.test(navigator.userAgent) ? + RegExp['x241'] : undefined; 513 514 //判断是否为gecko内核 515 $.browser.isGecko = /gecko/i.test(navigator.userAgent) && !/like gecko/i.test(navigator.userAgent); 516 517 //判断是否为webkit内核 518 $.browser.isWebkit = /webkit/i.test(navigator.userAgent); 519 520 //判断是否严格标准的渲染模式 521 $.browser.isStrict = document.compatMode == "CSS1Compat"; 522 523 $.browser.opera = /opera(/| )(d+(.d+)?)(.+?(version/(d+(.d+)?)))?/i.test(navigator.userAgent) ? + ( RegExp["x246"] || RegExp["x242"] ) : undefined; 524 525 (function(){ 526 var ua = navigator.userAgent; 527 /** 528 * 判断是否为safari浏览器, 支持ipad 529 * @property safari safari版本号 530 * @grammar $.browser.safari 531 */ 532 $.browser.safari = /(d+.d)?(?:.d)?s+safari/?(d+.d+)?/i.test(ua) && !/chrome/i.test(ua) ? + (RegExp['x241'] || RegExp['x242']) : undefined; 533 })(); 534 })(jQuery); 535 536 537 ;(function($){ 538 /** 539 * 判断平台类型和特性的属性 540 */ 541 $.platform = $.platform || {}; 542 543 /** 544 * 判断是否为android平台 545 */ 546 $.platform.isAndroid = /android/i.test(navigator.userAgent); 547 548 549 /** 550 * 判断是否为ipad平台 551 */ 552 $.platform.isIpad = /ipad/i.test(navigator.userAgent); 553 554 /** 555 * 判断是否为iphone平台 556 */ 557 $.platform.isIphone = /iphone/i.test(navigator.userAgent); 558 559 560 /** 561 * 判断是否为macintosh平台 562 */ 563 $.platform.isMacintosh = /macintosh/i.test(navigator.userAgent); 564 565 566 567 /** 568 * 判断是否为windows平台 569 */ 570 $.platform.isWindows = /windows/i.test(navigator.userAgent); 571 572 573 574 /** 575 * 判断是否为x11平台 576 */ 577 $.platform.isX11 = /x11/i.test(navigator.userAgent); 578 })(jQuery); 579 580 581 ;(function($){ 582 /** 583 * String增强 584 */ 585 $.string = $.string || {}; 586 587 /** 588 * 对目标字符串进行html解码 589 * @grammar $.string.decodeHTML(source) 590 * @param {string} source 目标字符串 591 * 592 * @returns {string} html解码后的字符串 593 */ 594 $.string.decodeHTML = function (source) { 595 var str = String(source) 596 .replace(/"/g,'"') 597 .replace(/</g,'<') 598 .replace(/>/g,'>') 599 .replace(/&/g, "&"); 600 //处理转义的中文和实体字符 601 return str.replace(/&#([d]+);/g, function(_0, _1){ 602 return String.fromCharCode(parseInt(_1, 10)); 603 }); 604 }; 605 606 /** 607 * 对目标字符串进行html编码 608 * @grammar $.string.encodeHTML(source) 609 * @param {string} source 目标字符串 610 * 编码字符有5个:&<>"' 611 * 612 * @returns {string} html编码后的字符串 613 */ 614 $.string.encodeHTML = function (source) { 615 return String(source) 616 .replace(/&/g,'&') 617 .replace(/</g,'<') 618 .replace(/>/g,'>') 619 .replace(/"/g, """) 620 .replace(/'/g, "'"); 621 }; 622 623 /** 624 * 去掉字符串中的html标签 625 * @function 626 * @grammar $.string.stripTags(source) 627 * @param {string} source 要处理的字符串. 628 * @return {String} 629 */ 630 $.string.stripTags = function(source) { 631 return String(source || '').replace(/<[^>]+>/g, ''); 632 }; 633 634 /** 635 * 将目标字符串中可能会影响正则表达式构造的字符串进行转义。 636 * @grammar $.string.escapeReg(source) 637 * @param {string} source 目标字符串 638 * @remark 639 * 给以下字符前加上“”进行转义:.*+?^=!:${}()|[]/ 640 * 641 * @returns {string} 转义后的字符串 642 */ 643 $.string.escapeReg = function (source) { 644 return String(source) 645 .replace(new RegExp("([.*+?^=!:x24{}()|[\]/\\])", "g"), '\x241'); 646 }; 647 648 /** 649 * 删除目标字符串两端的空白字符 650 * @grammar $.string.trim(source) 651 * @param {string} source 目标字符串 652 * @remark 653 * 不支持删除单侧空白字符 654 * 655 * @returns {string} 删除两端空白字符后的字符串 656 */ 657 658 (function () { 659 var trimer = new RegExp("(^[\s\t\xa0\u3000]+)|([\u3000\xa0\s\t]+x24)", "g"); 660 661 $.string.trim = function (source) { 662 return String(source) 663 .replace(trimer, ""); 664 }; 665 })(); 666 })(jQuery); 667 668 669 ;(function($){ 670 /** 671 * GUID 672 */ 673 $.lang = $.lang || {}; 674 /** 675 * 返回一个当前页面的唯一标识字符串。 676 * @grammar $.lang.guid() 677 * 678 * @returns {String} 当前页面的唯一标识字符串 679 */ 680 $.lang.guid = function() { 681 return "TANGRAM$" + $.lang._counter ++; 682 }; 683 684 //不直接使用window,可以提高3倍左右性能 685 $.lang._counter = $.lang._counter || 1; 686 $.guid = $.lang.guid;//设置$.page.guid别名$.guid 687 688 689 /** 690 * 判断目标参数是否为function或Function实例 691 * @grammar $.lang.isFunction(source) 692 * @param {Any} source 目标参数 693 * @returns {boolean} 类型判断结果 694 */ 695 $.lang.isFunction = function (source) { 696 // chrome下,'function' == typeof /a/ 为true. 697 return '[object Function]' == Object.prototype.toString.call(source); 698 }; 699 700 /** 701 * 判断目标参数是否为Element对象 702 * @grammar $.lang.isElement(source) 703 * @param {Any} source 目标参数 704 * @returns {boolean} 类型判断结果 705 */ 706 $.lang.isElement = function (source) { 707 return !!(source && source.nodeName && source.nodeType == 1); 708 }; 709 710 /** 711 * 判断目标参数是否Array对象 712 * @grammar $.lang.isArray(source) 713 * @param {Any} source 目标参数 714 * @returns {boolean} 类型判断结果 715 */ 716 $.lang.isArray = function (source) { 717 return '[object Array]' == Object.prototype.toString.call(source); 718 }; 719 })(jQuery); 720 721 ;(function($){ 722 /** 723 * Array增强 724 */ 725 $.array = $.array || {}; 726 727 /** 728 * 查询数组中指定元素的索引位置 729 * @grammar $.array.indexOf(source, match[, fromIndex]) 730 * @param {Array} source 需要查询的数组 731 * @param {Any} match 查询项 732 * @param {number} [fromIndex] 查询的起始位索引位置,如果为负数,则从source.length+fromIndex往后开始查找 733 * 734 * @returns {number} 指定元素的索引位置,查询不到时返回-1 735 */ 736 $.array.indexOf = function (source, match, fromIndex) { 737 var len = source.length, 738 iterator = match; 739 740 fromIndex = fromIndex | 0; 741 if(fromIndex < 0){//小于0 742 fromIndex = Math.max(0, len + fromIndex) 743 } 744 for ( ; fromIndex < len; fromIndex++) { 745 if(fromIndex in source && source[fromIndex] === match) { 746 return fromIndex; 747 } 748 } 749 750 return -1; 751 }; 752 753 /** 754 * 判断一个数组中是否包含给定元素 755 * @grammar $.array.contains(source, obj) 756 * @param {Array} source 需要判断的数组. 757 * @param {Any} obj 要查找的元素. 758 * @return {boolean} 判断结果. 759 * @author berg 760 */ 761 $.array.contains = function(source, obj) { 762 return ($.array.indexOf(source, obj) >= 0); 763 }; 764 765 /** 766 * 清空一个数组 767 * @grammar $.array.empty(source) 768 * @param {Array} source 需要清空的数组. 769 * @author berg 770 */ 771 $.array.empty = function(source) { 772 source.length = 0; 773 }; 774 775 /** 776 * 从后往前,查询数组中指定元素的索引位置 777 * @grammar $.array.lastIndexOf(source, match) 778 * @param {Array} source 需要查询的数组 779 * @param {Any} match 查询项 780 * @param {number} [fromIndex] 查询的起始位索引位置,如果为负数,则从source.length+fromIndex往前开始查找 781 * 782 * @returns {number} 指定元素的索引位置,查询不到时返回-1 783 */ 784 785 $.array.lastIndexOf = function (source, match, fromIndex) { 786 var len = source.length; 787 788 fromIndex = fromIndex | 0; 789 790 if(!fromIndex || fromIndex >= len){ 791 fromIndex = len - 1; 792 } 793 if(fromIndex < 0){ 794 fromIndex += len; 795 } 796 for(; fromIndex >= 0; fromIndex --){ 797 if(fromIndex in source && source[fromIndex] === match){ 798 return fromIndex; 799 } 800 } 801 802 return -1; 803 }; 804 805 /** 806 * 遍历数组中所有元素,将每一个元素应用方法进行转换,并返回转换后的新数组。 807 * @grammar $.array.map(source, iterator[, thisObject]) 808 * @param {Array} source 需要遍历的数组. 809 * @param {Function} iterator 对每个数组元素进行处理的函数. 810 * @param {Object} [thisObject] 函数调用时的this指针,如果没有此参数,默认是当前遍历的数组 811 * @return {Array} map后的数组. 812 */ 813 $.array.map = function(source, iterator, thisObject) { 814 var results = [], 815 i = 0, 816 l = source.length; 817 for (; i < l; i++) { 818 results[i] = iterator.call(thisObject || source, source[i], i); 819 } 820 return results; 821 }; 822 823 /** 824 * 遍历数组中所有元素,将每一个元素应用方法进行合并,并返回合并后的结果。 825 * @grammar $.array.reduce(source, iterator[, initializer]) 826 * @param {Array} source 需要遍历的数组. 827 * @param {Function} iterator 对每个数组元素进行处理的函数,函数接受四个参数:上一次reduce的结果(或初始值),当前元素值,索引值,整个数组. 828 * @param {Object} [initializer] 合并的初始项,如果没有此参数,默认用数组中的第一个值作为初始值. 829 * @return {Array} reduce后的值. 830 */ 831 $.array.reduce = function(source, iterator, initializer) { 832 var i = 0, 833 l = source.length, 834 found = 0; 835 836 if( arguments.length < 3){ 837 //没有initializer的情况,找到第一个可用的值 838 for(; i < l; i++){ 839 initializer = source[i++]; 840 found = 1; 841 break; 842 } 843 if(!found){ 844 return ; 845 } 846 } 847 848 for (; i < l; i++) { 849 if( i in source){ 850 initializer = iterator(initializer, source[i] , i , source); 851 } 852 } 853 return initializer; 854 }; 855 856 /** 857 * 移除数组中的项 858 * @grammar $.array.remove(source, match) 859 * @param {Array} source 需要移除项的数组 860 * @param {Any} match 要移除的项 861 * 862 * @returns {Array} 移除后的数组 863 */ 864 $.array.remove = function (source, match) { 865 var len = source.length; 866 867 while (len--) { 868 if (len in source && source[len] === match) { 869 source.splice(len, 1); 870 } 871 } 872 return source; 873 }; 874 875 /** 876 * 移除数组中的项 877 * @grammar $.array.removeAt(source, index) 878 * @param {Array} source 需要移除项的数组 879 * @param {number} index 要移除项的索引位置 880 * @returns {Any} 被移除的数组项 881 */ 882 $.array.removeAt = function (source, index) { 883 return source.splice(index, 1)[0]; 884 }; 885 886 /** 887 * 过滤数组中的相同项。如果两个元素相同,会删除后一个元素。 888 * @grammar $.array.unique(source[, compareFn]) 889 * @param {Array} source 需要过滤相同项的数组 890 * @param {Function} [compareFn] 比较两个数组项是否相同的函数,两个数组项作为函数的参数。 891 * 892 * @returns {Array} 过滤后的新数组 893 */ 894 $.array.unique = function (source, compareFn) { 895 var len = source.length, 896 result = source.slice(0), 897 i, datum; 898 899 if ('function' != typeof compareFn) { 900 compareFn = function (item1, item2) { 901 return item1 === item2; 902 }; 903 } 904 905 // 从后往前双重循环比较 906 // 如果两个元素相同,删除后一个 907 while (--len > 0) { 908 datum = result[len]; 909 i = len; 910 while (i--) { 911 if (compareFn(datum, result[i])) { 912 result.splice(len, 1); 913 break; 914 } 915 } 916 } 917 918 return result; 919 }; 920 })(jQuery); 921 922 ;(function(){ 923 /** 924 * 操作cookie的方法 925 * @namespace $.cookie 926 */ 927 $.cookie = $.cookie || {}; 928 929 /** 930 * 验证字符串是否合法的cookie键名 931 * 932 * @param {string} source 需要遍历的数组 933 * @meta standard 934 * @return {boolean} 是否合法的cookie键名 935 */ 936 $.cookie._isValidKey = function (key) { 937 // http://www.w3.org/Protocols/rfc2109/rfc2109 938 // Syntax: General 939 // The two state management headers, Set-Cookie and Cookie, have common 940 // syntactic properties involving attribute-value pairs. The following 941 // grammar uses the notation, and tokens DIGIT (decimal digits) and 942 // token (informally, a sequence of non-special, non-white space 943 // characters) from the HTTP/1.1 specification [RFC 2068] to describe 944 // their syntax. 945 // av-pairs = av-pair *(";" av-pair) 946 // av-pair = attr ["=" value] ; optional value 947 // attr = token 948 // value = word 949 // word = token | quoted-string 950 951 // http://www.ietf.org/rfc/rfc2068.txt 952 // token = 1*<any CHAR except CTLs or tspecials> 953 // CHAR = <any US-ASCII character (octets 0 - 127)> 954 // CTL = <any US-ASCII control character 955 // (octets 0 - 31) and DEL (127)> 956 // tspecials = "(" | ")" | "<" | ">" | "@" 957 // | "," | ";" | ":" | "" | <"> 958 // | "/" | "[" | "]" | "?" | "=" 959 // | "{" | "}" | SP | HT 960 // SP = <US-ASCII SP, space (32)> 961 // HT = <US-ASCII HT, horizontal-tab (9)> 962 963 return (new RegExp("^[^\x00-\x20\x7f\(\)<>@,;:\\\"\[\]\?=\{\}\/\u0080-\uffff]+x24")).test(key); 964 }; 965 966 /** 967 * 获取cookie的值,不对值进行解码 968 * @grammar $.cookie.getRaw(key) 969 * @param {string} key 需要获取Cookie的键名 970 * @returns {string|null} 获取的Cookie值,获取不到时返回null 971 */ 972 $.cookie.getRaw = function (key) { 973 if ($.cookie._isValidKey(key)) { 974 var reg = new RegExp("(^| )" + key + "=([^;]*)(;|x24)"), 975 result = reg.exec(document.cookie); 976 977 if (result) { 978 return result[2] || null; 979 } 980 } 981 982 return null; 983 }; 984 985 /** 986 * 设置cookie的值,不对值进行编码 987 * @grammar $.cookie.setRaw(key, value[, options]) 988 * @param {string} key 需要设置Cookie的键名 989 * @param {string} value 需要设置Cookie的值 990 * @param {Object} [options] 设置Cookie的其他可选参数 991 * @config {string} [path] cookie路径 992 * @config {Date|number} [expires] cookie过期时间,如果类型是数字的话, 单位是毫秒 993 * @config {string} [domain] cookie域名 994 * @config {string} [secure] cookie是否安全传输 995 * @remark 996 * 997 <b>options参数包括:</b><br> 998 path:cookie路径<br> 999 expires:cookie过期时间,Number型,单位为毫秒。<br> 1000 domain:cookie域名<br> 1001 secure:cookie是否安全传输 1002 */ 1003 $.cookie.setRaw = function (key, value, options) { 1004 if (!$.cookie._isValidKey(key)) { 1005 return; 1006 } 1007 1008 options = options || {}; 1009 //options.path = options.path || "/"; // meizz 20100402 设定一个初始值,方便后续的操作 1010 //berg 20100409 去掉,因为用户希望默认的path是当前路径,这样和浏览器对cookie的定义也是一致的 1011 1012 // 计算cookie过期时间 1013 var expires = options.expires; 1014 if ('number' == typeof options.expires) { 1015 expires = new Date(); 1016 expires.setTime(expires.getTime() + options.expires); 1017 } 1018 1019 document.cookie = 1020 key + "=" + value 1021 + (options.path ? "; path=" + options.path : "") 1022 + (expires ? "; expires=" + expires.toGMTString() : "") 1023 + (options.domain ? "; domain=" + options.domain : "") 1024 + (options.secure ? "; secure" : ''); 1025 }; 1026 1027 /** 1028 * 删除cookie的值 1029 * @grammar $.cookie.remove(key, options) 1030 * @param {string} key 需要删除Cookie的键名 1031 * @param {Object} options 需要删除的cookie对应的 path domain 等值 1032 */ 1033 $.cookie.remove = function (key, options) { 1034 options = options || {}; 1035 options.expires = new Date(0); 1036 $.cookie.setRaw(key, '', options); 1037 }; 1038 1039 /** 1040 * 获取cookie的值,用decodeURIComponent进行解码 1041 * @grammar $.cookie.get(key) 1042 * @param {string} key 需要获取Cookie的键名 1043 * @remark 1044 * <b>注意:</b>该方法会对cookie值进行decodeURIComponent解码。如果想获得cookie源字符串,请使用getRaw方法。 1045 * 1046 * @returns {string|null} cookie的值,获取不到时返回null 1047 */ 1048 $.cookie.get = function (key) { 1049 var value = $.cookie.getRaw(key); 1050 if ('string' == typeof value) { 1051 value = decodeURIComponent(value); 1052 return value; 1053 } 1054 return null; 1055 }; 1056 1057 /** 1058 * 设置cookie的值,用encodeURIComponent进行编码 1059 * @grammar $.cookie.set(key, value[, options]) 1060 * @param {string} key 需要设置Cookie的键名 1061 * @param {string} value 需要设置Cookie的值 1062 * @param {Object} [options] 设置Cookie的其他可选参数 1063 * @config {string} [path] cookie路径 1064 * @config {Date|number} [expires] cookie过期时间,如果类型是数字的话, 单位是毫秒 1065 * @config {string} [domain] cookie域名 1066 * @config {string} [secure] cookie是否安全传输 1067 * @remark 1068 * 1069 1. <b>注意:</b>该方法会对cookie值进行encodeURIComponent编码。如果想设置cookie源字符串,请使用setRaw方法。<br><br> 1070 2. <b>options参数包括:</b><br> 1071 path:cookie路径<br> 1072 expires:cookie过期时间,Number型,单位为毫秒。<br> 1073 domain:cookie域名<br> 1074 secure:cookie是否安全传输 1075 */ 1076 $.cookie.set = function (key, value, options) { 1077 $.cookie.setRaw(key, encodeURIComponent(value), options); 1078 }; 1079 })(jQuery); 1080 1081 ;(function($){ 1082 $.number = $.number || {}; 1083 1084 /** 1085 * 为目标数字添加逗号分隔 1086 * @grammar $.number.comma(source[, length]) 1087 * @param {number} source 需要处理的数字 1088 * @param {number} [length] 两次逗号之间的数字位数,默认为3位 1089 * 1090 * @returns {string} 添加逗号分隔后的字符串 1091 */ 1092 $.number.comma = function (source, length) { 1093 if (!length || length < 1) { 1094 length = 3; 1095 } 1096 1097 source = String(source).split("."); 1098 source[0] = source[0].replace(new RegExp('(\d)(?=(\d{'+length+'})+$)','ig'),"$1,"); 1099 return source.join("."); 1100 }; 1101 1102 /** 1103 * 生成随机整数,范围是[min, max] 1104 * @grammar $.number.randomInt(min, max) 1105 * 1106 * @param {number} min 随机整数的最小值 1107 * @param {number} max 随机整数的最大值 1108 * @return {number} 生成的随机整数 1109 */ 1110 $.number.randomInt = function(min, max){ 1111 return Math.floor(Math.random() * (max - min + 1) + min); 1112 }; 1113 1114 /** 1115 * 对目标数字进行0补齐处理 1116 * @grammar $.number.pad(source, length) 1117 * @param {number} source 需要处理的数字 1118 * @param {number} length 需要输出的长度 1119 * 1120 * @returns {string} 对目标数字进行0补齐处理后的结果 1121 */ 1122 $.number.pad = function (source, length) { 1123 var pre = "", 1124 negative = (source < 0), 1125 string = String(Math.abs(source)); 1126 1127 if (string.length < length) { 1128 pre = (new Array(length - string.length + 1)).join('0'); 1129 } 1130 1131 return (negative ? "-" : "") + pre + string; 1132 }; 1133 })(jQuery); 1134 1135 ;(function($){ 1136 $.sio = $.sio || {}; 1137 /** 1138 * 通过请求一个图片的方式令服务器存储一条日志 1139 * @grammar $.sio.log(url) 1140 * @param {string} url 要发送的地址. 1141 */ 1142 $.sio.log = function(url) { 1143 var img = new Image(), 1144 key = 'tangram_sio_log_' + Math.floor(Math.random() * 1145 2147483648).toString(36); 1146 1147 // 这里一定要挂在window下 1148 // 在IE中,如果没挂在window下,这个img变量又正好被GC的话,img的请求会abort 1149 // 导致服务器收不到日志 1150 window[key] = img; 1151 1152 img.onload = img.onerror = img.onabort = function() { 1153 // 下面这句非常重要 1154 // 如果这个img很不幸正好加载了一个存在的资源,又是个gif动画 1155 // 则在gif动画播放过程中,img会多次触发onload 1156 // 因此一定要清空 1157 img.onload = img.onerror = img.onabort = null; 1158 1159 window[key] = null; 1160 1161 // 下面这句非常重要 1162 // new Image创建的是DOM,DOM的事件中形成闭包环引用DOM是典型的内存泄露 1163 // 因此这里一定要置为null 1164 img = null; 1165 }; 1166 1167 // 一定要在注册了事件之后再设置src 1168 // 不然如果图片是读缓存的话,会错过事件处理 1169 // 最后,对于url最好是添加客户端时间来防止缓存 1170 // 同时服务器也配合一下传递Cache-Control: no-cache; 1171 img.src = url; 1172 }; 1173 })(jQuery); 1174 1175 1176 ;(function($){ 1177 $.url = $.url || {}; 1178 /** 1179 * 对字符串进行%#&+=以及和s匹配的所有字符进行url转义 1180 * @grammar $.url.escapeSymbol(source) 1181 * @param {string} source 需要转义的字符串. 1182 * @return {string} 转义之后的字符串. 1183 * @remark 1184 * 用于get请求转义。在服务器只接受gbk,并且页面是gbk编码时,可以经过本转义后直接发get请求。 1185 * 1186 * @return {string} 转义后的字符串 1187 */ 1188 $.url.escapeSymbol = function(source) { 1189 1190 //TODO: 之前使用s来匹配任意空白符 1191 //发现在ie下无法匹配中文全角空格和纵向指标符v,所以改s为f v以及中文全角空格和英文空格 1192 //但是由于ie本身不支持纵向指标符v,故去掉对其的匹配,保证各浏览器下效果一致 1193 return String(source).replace(/[#%&+=/\ f ]/g, function(all) { 1194 return '%' + (0x100 + all.charCodeAt()).toString(16).substring(1).toUpperCase(); 1195 }); 1196 }; 1197 1198 /** 1199 * 根据参数名从目标URL中获取参数值 1200 * @grammar $.url.getQueryValue(url, key) 1201 * @param {string} url 目标URL 1202 * @param {string} key 要获取的参数名 1203 * 1204 * @returns {string|null} - 获取的参数值,其中URI编码后的字符不会被解码,获取不到时返回null 1205 */ 1206 $.url.getQueryValue = function (url, key) { 1207 var reg = new RegExp( 1208 "(^|&|\?|#)" 1209 + $.string.escapeReg(key) 1210 + "=([^&#]*)(&|x24|#)", 1211 ""); 1212 var match = url.match(reg); 1213 if (match) { 1214 return match[2]; 1215 } 1216 1217 return null; 1218 }; 1219 1220 /** 1221 * 将json对象解析成query字符串 1222 * @grammar $.url.jsonToQuery(json[, replacer]) 1223 * @param {Object} json 需要解析的json对象 1224 * @param {Function=} replacer_opt 对值进行特殊处理的函数,function (value, key) 1225 * 1226 * @return {string} - 解析结果字符串,其中值将被URI编码,{a:'&1 '} ==> "a=%261%20"。 1227 */ 1228 $.url.jsonToQuery = function (json, replacer_opt) { 1229 var result = [], 1230 itemLen, 1231 replacer = replacer_opt || function (value) { 1232 return $.url.escapeSymbol(value); 1233 }; 1234 1235 $.each(json, function(item, key){ 1236 // 这里只考虑item为数组、字符串、数字类型,不考虑嵌套的object 1237 if ($.lang.isArray(item)) { 1238 itemLen = item.length; 1239 // value的值需要encodeURIComponent转义吗? 1240 // FIXED 优化了escapeSymbol函数 1241 while (itemLen--) { 1242 result.push(key + '=' + replacer(item[itemLen], key)); 1243 } 1244 } else { 1245 result.push(key + '=' + replacer(item, key)); 1246 } 1247 }); 1248 1249 return result.join('&'); 1250 }; 1251 1252 1253 /** 1254 * 解析目标URL中的参数成json对象 1255 * @grammar $.url.queryToJson(url) 1256 * @param {string} url 目标URL 1257 * 1258 * @returns {Object} - 解析为结果对象,其中URI编码后的字符不会被解码,'a=%20' ==> {a:'%20'}。 1259 */ 1260 $.url.queryToJson = function (url) { 1261 var query = url.substr(url.lastIndexOf('?') + 1), 1262 params = query.split('&'), 1263 len = params.length, 1264 result = {}, 1265 i = 0, 1266 key, value, item, param; 1267 1268 for (; i < len; i++) { 1269 if(!params[i]){ 1270 continue; 1271 } 1272 param = params[i].split('='); 1273 key = param[0]; 1274 value = param[1]; 1275 1276 item = result[key]; 1277 if ('undefined' == typeof item) { 1278 result[key] = value; 1279 } else if ($.lang.isArray(item)) { 1280 item.push(value); 1281 } else { // 这里只可能是string了 1282 result[key] = [item, value]; 1283 } 1284 } 1285 1286 return result; 1287 }; 1288 })(jQuery);