js高级应用
特别板块:js跨域请求Tomcat6、tomcat7 跨域设置(包含html5 的CORS)
需要下载两个jar文件,cors-filter-1.7.jar,Java-property-utils-1.9.jar这两个库文件,http://download.csdn.net/detail/csr0312/9280097
放到tomcat lib目录下面,不是项目的lib目录,然后配置项目的web.xml,添加如下内容,注意filter位置,应该放在第一位
<!-- 实现跨域 --> <filter> <filter-name>CORS</filter-name> <filter-class>com.thetransactioncompany.cors.CORSFilter</filter-class> <init-param><!-- 一般为了安全考虑会指定具体几个地址源 --> <param-name>cors.allowOrigin</param-name> <param-value>*</param-value> </init-param> <init-param> <param-name>cors.supportedMethods</param-name> <param-value>GET, POST, HEAD, PUT, DELETE</param-value> </init-param> <init-param><!-- 消息头设置 --> <param-name>cors.supportedHeaders</param-name> <param-value>Accept, Origin, X-Requested-With, Content-Type, Last-Modified,Access-Control-Allow-Origin</param-value> </init-param> <init-param> <param-name>cors.exposedHeaders</param-name> <param-value>Set-Cookie</param-value> </init-param> <init-param> <param-name>cors.supportsCredentials</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>CORS</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
0、js版本检测
<html> <head> <title>JavaScript版本测试</title> </head> <body> <script language="JavaScript"> //仅支持JavaScript 1.0的浏览器才读该部分 document.write('浏览器支持JavaScript 1.0<br>'); </script> <script language="JavaScript1.1"> //仅支持JavaScript 1.1的浏览器才读该部分 document.write('浏览器支持JavaScript 1.1<br>'); </script> <script language="JavaScript1.2"> //仅支持JavaScript 1.2的浏览器才读该部分 document.write('浏览器支持JavaScript 1.2<br>'); </script> <script language="JavaScript1.3"> //仅支持JavaScript 1.3的浏览器才读该部分 document.write('浏览器支持JavaScript 1.3<br>'); </script> <script language="JavaScript1.4"> //仅支持JavaScript 1.4的浏览器才读该部分 document.write('浏览器支持JavaScript 1.4<br>'); </script> <script language="JavaScript1.5"> //仅支持JavaScript 1.5的浏览器才读该部分 document.write('浏览器支持JavaScript 1.5<br>'); </script> <script language="JavaScript1.6"> //仅支持JavaScript 1.6的浏览器才读该部分 document.write('浏览器支持JavaScript 1.6<br>'); </script> <script language="JavaScript1.7"> //仅支持JavaScript 1.7的浏览器才读该部分 document.write('浏览器支持JavaScript 1.7<br>'); </script> <script language="JavaScript1.8"> //仅支持JavaScript 1.8的浏览器才读该部分 document.write('浏览器支持JavaScript 1.8<br>'); </script> <script language="JavaScript1.9"> //仅支持JavaScript 1.9的浏览器才读该部分 document.write('浏览器支持JavaScript 1.9<br>'); </script> </body> </html>
1、trigger
情景:在项目中,tab页切换时,元素无法正常显示出来,拖动窗口大小时,又能正常显示;
可在tab的切换点击事件中加入该操作:
$(window).trigger("resize",$(window).width(),$(window).height()); 即重置窗口大小,实现拖动窗口效果。
2、$.attr()问题:
情景:<input id="tt" clickEvent="sendInfo('info')"> ,
$("#tt").attr("clickEvent") 结果取出来的是“sendInfo(”,
因为该代码经过浏览器解析后,变成<input id='tt' clickEvent='sendInfo('info')'>,故有此结果;
如果属性是通过后台拼接,该问题更突出(如:java中的标签)。
处理方法:1、改写成:<input id="tt" clickEvent='sendInfo("info")'>
2、案例:
字符串1:{"cityId":"110100","cityName":"北京市辖区"}
字符串2:{"cityId":"110100","cityName":"北京市辖区"}
如上字符串所示,字符串1是在java后台生成,通过structs2传递到前台后,js中取得的字符串却变成了字符串2的样子,
其中的”变成了"使用的时候用StringEscapeUtils.unescapeHtml(字符串2)) 解下码就行,便可取得原字符串1。
由以上可以找到解决方案:
1、后台传前台:[如json字符串].replaceAll("[\"']", """),先将字符串中的单引号和双引号转出""",
传到前台后浏览器会自动解析格式;
2、前台传后台:都是自己写的,这个就不要偷懒啦,注意下格式就行了。
3、jquery简雅之美:
1)、简雅之美 - 高兼容事件绑定
比如input的值改变事件,正常我们可能都会想到onpropertychange事件,于是这样操作:
$(ob).bind("propertychange",function(){ ...... });
但是问题又来了,onpropertychange事件是ie专有的,可恶的是还只是ie9一下的版本才能有效;
那ie9及以上版本咋整?不急还有oninput事件,于是写下如下代码:
$(ob).bind("input",function(){ ...... });
然这样并没有解决问题,这种照顾了ie9及以上版本却照顾不了ie8等低版本,不急我们可以这样写:
$(ob).bind("input propertychange",function(){ ...... });于是问题解决了。
绑定事件如此写,其实可以看成是事件选择器,既优雅又简洁。
4、js判断输入字符串长度(汉字算两个字符,字母数字算一个)
汉字在数据库中占2个字符,如果输入字符超过数据库表字段长度,会出现错误,因此需要在前台进行判断。有两种方法进行判断:
方法一:使用正则表达式,代码如下:
function getByteLen(val) { var len = 0; for (var i = 0; i < val.length; i++) { var a = val.charAt(i); if (a.match(/[^\x00-\xff]/ig) != null) { len += 2; } else { len += 1; } } return len; }
方法二:使用字符unicode判断:方法如下:
function getByteLen(val) { var len = 0; for (var i = 0; i < val.length; i++) { var length = val.charCodeAt(i); if(length>=0&&length<=128) { len += 1; } else { len += 2; } } return len; }
5、比较完美的日期格式化
a、(如jsp)头部引入标签<%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
b、利用<fmt:formatDate value="${obj.date}" pattern="yyyy-M-d" />嵌套到要初始化的输入域:
<input type="text" value="<fmt:formatDate value="${obj.date}" pattern="yyyy-M-d" />"/>
js之字符串转日期:建议使用 'yyyy/MM/dd' 格式,'yyyy-MM-dd' 这种格式在ie9以下时容易出现NoN解析异常
即:var date1 = new Date('2016/01/01'); (兼容性好)
var date2 = new Date('2016-01-01'); (ie9以下易出问题)
如果非要出入'yyyy-MM-dd' 格式,如下处理
dateStr = '2016-01-01';
var date2 = new Date(Date.parse(dateStr.replace(/-/g, "/")));
6、调用iframe里的js函数
如: document.getElementById('iframedemo').targetfunction();
但是这段代码在firefox下报错,于是上google搜索,发现一个解决办法,在ie和firefox 下均工作正常,代码如下:
document.getElementById('iframedemo').contentWindow.demofunction();
其中iframedemo是iframe的id
7、纯js事件追加之window.addEventListener
window.addEventListener('resize',method1);
window.addEventListener('resize',method2);
window.addEventListener('resize',method3);
执行顺序为:method1 -> method2 -> method3
例如图表插件Echarts在setoption之后添加这段代码:
window.addEventListener('resize', function () {
myChart.resize();
});
图表就能随着窗口大小,自动适应,且支持一页多图。
8、监测js加载
场景:项目中监测js或者css是否重复加载,避免冗余请求,减轻后端压力
<!-- Bootstrap core JavaScript --> <script src="/js/jquery/jquery-1.8.3.min.js"></script> <script src="/js/bootstrap/js/bootstrap.min.js"></script> <script src="/js/framework/jquery.menu.js"></script> <script src="/js/framework/jquery.menu.js"></script> <script src="/portal/common/js/jquery-easyui/jquery.easyui.min.js"></script> <script type="text/javascript"> var msg = []; $("script").each(function(){ var item = $(this); $("script").each(function(){ var innerItem = $(this); if(item.attr("src")==innerItem.attr("src")){ var count = $("script[src*='"+item.attr("src")+"']").size() || 0; if(count>1){ var itemInfo = item.attr("src")+":"+count+"\n"; if($.inArray(itemInfo,msg)<0){ msg.push(itemInfo); } } } }); }); if(msg!=""){ $.messager.alert("提示",msg); } </script>
输出结果:/js/framework/jquery.menu.js:2
9、form表单提交巧技 -- post传参方式打开新窗口
// 打开新窗口post方式提交,target是关键 function submitForm(url,param){ var form = $("<form anction='"+url+"' method='post' target='_blank' style='width: 0px;height: 0px;'></form>").appendTo(document.body); for(var item in subParam){ var input = $("<input type='hidden' name='"+item+"' value='"+param[item]+"'/>"); form.append(input); } form.submit(); form.remove(); }
这样封装之后,是不是超好用捏O(∩_∩)O
10、js函数类Math之最大值max和最小值min
var a=[1,2,3,5]; alert(Math.max.apply(null, a));//最大值 alert(Math.min.apply(null, a));//最小值 多维数组 var a=[1,2,3,[5,6],[1,4,8]]; var ta=a.join(",").split(",");//转化为一维数组 alert(Math.max.apply(null,ta));//最大值 alert(Math.min.apply(null,ta));//最小值 使用链式 Array.prototype.max = function() { return Math.max.apply({},this) } Array.prototype.min = function() { return Math.min.apply({},this) } [1, 2, 3].max()// => 3 [1, 2, 3].min()// => 1 使用方法[1,2,3].max() Array.max = function(array) { return Math.max.apply(Math, array); }; Array.min = function(array) { return Math.min.apply(Math, array); };
11、js之apply和call方法详解
js apply和js call方法总是让初学者困惑,下文就apply和call的区别,什么情况下用apply,什么情况下用call、apply的巧妙用法来阐述js apply和js call方法的详细使用方法。
主要我是要解决一下几个问题:
1. apply和call的区别在哪里
2. 什么情况下用apply,什么情况下用call
3. apply的其他巧妙用法(一般在什么情况下可以使用apply)
apply:方法能劫持另外一个对象的方法,继承另外一个对象的属性.
Function.apply(obj,args)方法能接收两个参数:
obj:这个对象将代替Function类里this对象
args:这个是数组,它将作为参数传给Function(args-->arguments)
call:和apply的意思一样,只不过是参数列表不一样.
Function.call(obj,[param1[,param2[,…[,paramN]]]])
obj:这个对象将代替Function类里this对象
params:这个是一个参数列表
1. apply示例:
js apply和js call方法详解
分析: Person.apply(this,arguments);
this:在创建对象在这个时候代表的是student
arguments:是一个数组,也就是[“zhangsan”,”21”,”一年级”];
也就是通俗一点讲就是:用student去执行Person这个类里面的内容,在Person这个类里面存在this.name等之类的语句,这样就将属性创建到了student对象里面
2. call示例
在Studen函数里面可以将apply中修改成如下:
Person.call(this,name,age);
这样就ok了
3.什么情况下用apply,什么情况下用call
在给对象参数的情况下,如果参数的形式是数组的时候,比如apply示例里面传递了参数arguments,这个参数是数组类型,并且在调用Person的时候参数的列表是对应一致的(也就是Person和Student的参数列表前两位是一致的) 就可以采用 apply , 如果我的Person的参数列表是这样的(age,name),而Student的参数列表是(name,age,grade),这样就可以用call来实现了,也就是直接指定参数列表对应值的位置(Person.call(this,age,name,grade));
4. apply的一些其他巧妙用法
细心的人可能已经察觉到,在我调用apply方法的时候,第一个参数是对象(this), 第二个参数是一个数组集合, 在调用Person的时候,他需要的不是一个数组,但是为什么他给我一个数组我仍然可以将数组解析为一个一个的参数,这个就是apply的一个巧妙的用处,可以将一个数组默认的转换为一个参数列表([param1,param2,param3] 转换为 param1,param2,param3) 这个如果让我们用程序来实现将数组的每一个项,来装换为参数的列表,可能都得费一会功夫,借助apply的这点特性,所以就有了以下高效率的方法:
a) Math.max 可以实现得到数组中最大的一项
因为Math.max 参数里面不支持Math.max([param1,param2]) 也就是数组
但是它支持Math.max(param1,param2,param3…),所以可以根据刚才apply的那个特点来解决 var max=Math.max.apply(null,array),这样轻易的可以得到一个数组中最大的一项(apply会将一个数组装换为一个参数接一个参数的传递给方法)
这块在调用的时候第一个参数给了一个null,这个是因为没有对象去调用这个方法,我只需要用这个方法帮我运算,得到返回的结果就行,.所以直接传递了一个null过去
b) Math.min 可以实现得到数组中最小的一项
同样和 max是一个思想 var min=Math.min.apply(null,array);
c) Array.prototype.push 可以实现两个数组合并
同样push方法没有提供push一个数组,但是它提供了push(param1,param,…paramN) 所以同样也可以通过apply来装换一下这个数组,即:
vararr1=new Array("1","2","3");
vararr2=new Array("4","5","6");
Array.prototype.push.apply(arr1,arr2);
也可以这样理解,arr1调用了push方法,参数是通过apply将数组装换为参数列表的集合.
通常在什么情况下,可以使用apply类似Math.min等之类的特殊用法:
一般在目标函数只需要n个参数列表,而不接收一个数组的形式([param1[,param2[,…[,paramN]]]]),可以通过apply的方式巧妙地解决这个问题!
12、Map扩展
Map对象在ie下,是有兼容性问题的,ie9+才好使,为此只能扩展Map了
(function(win) { var Map = function() { this.count = 0; this.entrySet = {}; }; var proto = Map.prototype; proto.size = function() { return this.count; }; proto.isEmpty = function() { return this.count == 0; }; proto.containsKey = function(key) { if (this.isEmpty()) { return false; } for ( var prop in this.entrySet) { if (prop == key) { return true; } } return false; }; proto.containsValue = function(value) { if (this.isEmpty()) { return false; } for ( var key in this.entrySet) { if (this.entrySet[key] == value) { return true; } } return false; }; proto.get = function(key) { if (this.isEmpty()) { return null; } if (this.containsKey(key)) { return this.entrySet[key]; } return null; }; proto.put = function(key, value) { this.entrySet[key] = value; this.count++; }; proto.remove = function(key) { if (this.containsKey(key)) { delete this.entrySet[key]; this.count--; } }; proto.putAll = function(map) { if(!map instanceof Map){ return; } for ( var key in map.entrySet) { this.put(key, map.entrySet[key]); } }; proto.clear = function() { for ( var key in this.entrySet) { this.remove(key); } }; proto.values = function() { var result = []; for ( var key in this.entrySet) { result.push(this.entrySet[key]); } return result; }; proto.keySet = function() { var result = []; for ( var key in this.entrySet) { result.push(key); } return result; }; proto.toString = function() { var result = []; for ( var key in this.entrySet) { result.push(key + ":" + this.entrySet[key]); } return "{" + result.join() + "}"; }; proto.valueOf = function() { return this.toString(); }; win.Map = Map; })(window);
13、JSON.stringify()兼容扩展
源码:https://github.com/douglascrockford/JSON-js
这个JS中的函数将JSON对象转换成JSON字符串,解决 IE6、7、8不能使用 JSON.stringify 函数的问题!
<!--[if lt IE 9]>
<script src="json2.js"></script>
<![endif]-->
// json2.js // 2016-05-01 // Public Domain. // NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. // See http://www.JSON.org/js.html // This code should be minified before deployment. // See http://javascript.crockford.com/jsmin.html // USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO // NOT CONTROL. // This file creates a global JSON object containing two methods: stringify // and parse. This file is provides the ES5 JSON capability to ES3 systems. // If a project might run on IE8 or earlier, then this file should be included. // This file does nothing on ES5 systems. // JSON.stringify(value, replacer, space) // value any JavaScript value, usually an object or array. // replacer an optional parameter that determines how object // values are stringified for objects. It can be a // function or an array of strings. // space an optional parameter that specifies the indentation // of nested structures. If it is omitted, the text will // be packed without extra whitespace. If it is a number, // it will specify the number of spaces to indent at each // level. If it is a string (such as "\t" or " "), // it contains the characters used to indent at each level. // This method produces a JSON text from a JavaScript value. // When an object value is found, if the object contains a toJSON // method, its toJSON method will be called and the result will be // stringified. A toJSON method does not serialize: it returns the // value represented by the name/value pair that should be serialized, // or undefined if nothing should be serialized. The toJSON method // will be passed the key associated with the value, and this will be // bound to the value. // For example, this would serialize Dates as ISO strings. // Date.prototype.toJSON = function (key) { // function f(n) { // // Format integers to have at least two digits. // return (n < 10) // ? "0" + n // : n; // } // return this.getUTCFullYear() + "-" + // f(this.getUTCMonth() + 1) + "-" + // f(this.getUTCDate()) + "T" + // f(this.getUTCHours()) + ":" + // f(this.getUTCMinutes()) + ":" + // f(this.getUTCSeconds()) + "Z"; // }; // You can provide an optional replacer method. It will be passed the // key and value of each member, with this bound to the containing // object. The value that is returned from your method will be // serialized. If your method returns undefined, then the member will // be excluded from the serialization. // If the replacer parameter is an array of strings, then it will be // used to select the members to be serialized. It filters the results // such that only members with keys listed in the replacer array are // stringified. // Values that do not have JSON representations, such as undefined or // functions, will not be serialized. Such values in objects will be // dropped; in arrays they will be replaced with null. You can use // a replacer function to replace those with JSON values. // JSON.stringify(undefined) returns undefined. // The optional space parameter produces a stringification of the // value that is filled with line breaks and indentation to make it // easier to read. // If the space parameter is a non-empty string, then that string will // be used for indentation. If the space parameter is a number, then // the indentation will be that many spaces. // Example: // text = JSON.stringify(["e", {pluribus: "unum"}]); // // text is '["e",{"pluribus":"unum"}]' // text = JSON.stringify(["e", {pluribus: "unum"}], null, "\t"); // // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]' // text = JSON.stringify([new Date()], function (key, value) { // return this[key] instanceof Date // ? "Date(" + this[key] + ")" // : value; // }); // // text is '["Date(---current time---)"]' // JSON.parse(text, reviver) // This method parses a JSON text to produce an object or array. // It can throw a SyntaxError exception. // The optional reviver parameter is a function that can filter and // transform the results. It receives each of the keys and values, // and its return value is used instead of the original value. // If it returns what it received, then the structure is not modified. // If it returns undefined then the member is deleted. // Example: // // Parse the text. Values that look like ISO date strings will // // be converted to Date objects. // myData = JSON.parse(text, function (key, value) { // var a; // if (typeof value === "string") { // a = // /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value); // if (a) { // return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4], // +a[5], +a[6])); // } // } // return value; // }); // myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) { // var d; // if (typeof value === "string" && // value.slice(0, 5) === "Date(" && // value.slice(-1) === ")") { // d = new Date(value.slice(5, -1)); // if (d) { // return d; // } // } // return value; // }); // This is a reference implementation. You are free to copy, modify, or // redistribute. /*jslint eval, for, this */ /*property JSON, apply, call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours, getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join, lastIndex, length, parse, prototype, push, replace, slice, stringify, test, toJSON, toString, valueOf */ // Create a JSON object only if one does not already exist. We create the // methods in a closure to avoid creating global variables. if (typeof JSON !== "object") { JSON = {}; } (function () { "use strict"; var rx_one = /^[\],:{}\s]*$/; var rx_two = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g; var rx_three = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g; var rx_four = /(?:^|:|,)(?:\s*\[)+/g; var rx_escapable = /[\\\"\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g; var rx_dangerous = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g; function f(n) { // Format integers to have at least two digits. return n < 10 ? "0" + n : n; } function this_value() { return this.valueOf(); } if (typeof Date.prototype.toJSON !== "function") { Date.prototype.toJSON = function () { return isFinite(this.valueOf()) ? this.getUTCFullYear() + "-" + f(this.getUTCMonth() + 1) + "-" + f(this.getUTCDate()) + "T" + f(this.getUTCHours()) + ":" + f(this.getUTCMinutes()) + ":" + f(this.getUTCSeconds()) + "Z" : null; }; Boolean.prototype.toJSON = this_value; Number.prototype.toJSON = this_value; String.prototype.toJSON = this_value; } var gap; var indent; var meta; var rep; function quote(string) { // If the string contains no control characters, no quote characters, and no // backslash characters, then we can safely slap some quotes around it. // Otherwise we must also replace the offending characters with safe escape // sequences. rx_escapable.lastIndex = 0; return rx_escapable.test(string) ? "\"" + string.replace(rx_escapable, function (a) { var c = meta[a]; return typeof c === "string" ? c : "\\u" + ("0000" + a.charCodeAt(0).toString(16)).slice(-4); }) + "\"" : "\"" + string + "\""; } function str(key, holder) { // Produce a string from holder[key]. var i; // The loop counter. var k; // The member key. var v; // The member value. var length; var mind = gap; var partial; var value = holder[key]; // If the value has a toJSON method, call it to obtain a replacement value. if (value && typeof value === "object" && typeof value.toJSON === "function") { value = value.toJSON(key); } // If we were called with a replacer function, then call the replacer to // obtain a replacement value. if (typeof rep === "function") { value = rep.call(holder, key, value); } // What happens next depends on the value's type. switch (typeof value) { case "string": return quote(value); case "number": // JSON numbers must be finite. Encode non-finite numbers as null. return isFinite(value) ? String(value) : "null"; case "boolean": case "null": // If the value is a boolean or null, convert it to a string. Note: // typeof null does not produce "null". The case is included here in // the remote chance that this gets fixed someday. return String(value); // If the type is "object", we might be dealing with an object or an array or // null. case "object": // Due to a specification blunder in ECMAScript, typeof null is "object", // so watch out for that case. if (!value) { return "null"; } // Make an array to hold the partial results of stringifying this object value. gap += indent; partial = []; // Is the value an array? if (Object.prototype.toString.apply(value) === "[object Array]") { // The value is an array. Stringify every element. Use null as a placeholder // for non-JSON values. length = value.length; for (i = 0; i < length; i += 1) { partial[i] = str(i, value) || "null"; } // Join all of the elements together, separated with commas, and wrap them in // brackets. v = partial.length === 0 ? "[]" : gap ? "[\n" + gap + partial.join(",\n" + gap) + "\n" + mind + "]" : "[" + partial.join(",") + "]"; gap = mind; return v; } // If the replacer is an array, use it to select the members to be stringified. if (rep && typeof rep === "object") { length = rep.length; for (i = 0; i < length; i += 1) { if (typeof rep[i] === "string") { k = rep[i]; v = str(k, value); if (v) { partial.push(quote(k) + ( gap ? ": " : ":" ) + v); } } } } else { // Otherwise, iterate through all of the keys in the object. for (k in value) { if (Object.prototype.hasOwnProperty.call(value, k)) { v = str(k, value); if (v) { partial.push(quote(k) + ( gap ? ": " : ":" ) + v); } } } } // Join all of the member texts together, separated with commas, // and wrap them in braces. v = partial.length === 0 ? "{}" : gap ? "{\n" + gap + partial.join(",\n" + gap) + "\n" + mind + "}" : "{" + partial.join(",") + "}"; gap = mind; return v; } } // If the JSON object does not yet have a stringify method, give it one. if (typeof JSON.stringify !== "function") { meta = { // table of character substitutions "\b": "\\b", "\t": "\\t", "\n": "\\n", "\f": "\\f", "\r": "\\r", "\"": "\\\"", "\\": "\\\\" }; JSON.stringify = function (value, replacer, space) { // The stringify method takes a value and an optional replacer, and an optional // space parameter, and returns a JSON text. The replacer can be a function // that can replace values, or an array of strings that will select the keys. // A default replacer method can be provided. Use of the space parameter can // produce text that is more easily readable. var i; gap = ""; indent = ""; // If the space parameter is a number, make an indent string containing that // many spaces. if (typeof space === "number") { for (i = 0; i < space; i += 1) { indent += " "; } // If the space parameter is a string, it will be used as the indent string. } else if (typeof space === "string") { indent = space; } // If there is a replacer, it must be a function or an array. // Otherwise, throw an error. rep = replacer; if (replacer && typeof replacer !== "function" && (typeof replacer !== "object" || typeof replacer.length !== "number")) { throw new Error("JSON.stringify"); } // Make a fake root object containing our value under the key of "". // Return the result of stringifying the value. return str("", {"": value}); }; } // If the JSON object does not yet have a parse method, give it one. if (typeof JSON.parse !== "function") { JSON.parse = function (text, reviver) { // The parse method takes a text and an optional reviver function, and returns // a JavaScript value if the text is a valid JSON text. var j; function walk(holder, key) { // The walk method is used to recursively walk the resulting structure so // that modifications can be made. var k; var v; var value = holder[key]; if (value && typeof value === "object") { for (k in value) { if (Object.prototype.hasOwnProperty.call(value, k)) { v = walk(value, k); if (v !== undefined) { value[k] = v; } else { delete value[k]; } } } } return reviver.call(holder, key, value); } // Parsing happens in four stages. In the first stage, we replace certain // Unicode characters with escape sequences. JavaScript handles many characters // incorrectly, either silently deleting them, or treating them as line endings. text = String(text); rx_dangerous.lastIndex = 0; if (rx_dangerous.test(text)) { text = text.replace(rx_dangerous, function (a) { return "\\u" + ("0000" + a.charCodeAt(0).toString(16)).slice(-4); }); } // In the second stage, we run the text against regular expressions that look // for non-JSON patterns. We are especially concerned with "()" and "new" // because they can cause invocation, and "=" because it can cause mutation. // But just to be safe, we want to reject all unexpected forms. // We split the second stage into 4 regexp operations in order to work around // crippling inefficiencies in IE's and Safari's regexp engines. First we // replace the JSON backslash pairs with "@" (a non-JSON character). Second, we // replace all simple value tokens with "]" characters. Third, we delete all // open brackets that follow a colon or comma or that begin the text. Finally, // we look to see that the remaining characters are only whitespace or "]" or // "," or ":" or "{" or "}". If that is so, then the text is safe for eval. if ( rx_one.test( text .replace(rx_two, "@") .replace(rx_three, "]") .replace(rx_four, "") ) ) { // In the third stage we use the eval function to compile the text into a // JavaScript structure. The "{" operator is subject to a syntactic ambiguity // in JavaScript: it can begin a block or an object literal. We wrap the text // in parens to eliminate the ambiguity. j = eval("(" + text + ")"); // In the optional fourth stage, we recursively walk the new structure, passing // each name/value pair to a reviver function for possible transformation. return (typeof reviver === "function") ? walk({"": j}, "") : j; } // If the text is not JSON parseable, then a SyntaxError is thrown. throw new SyntaxError("JSON.parse"); }; } }());
14、javascript 变量加var 和 不加var区别
一、外部的为全局,内部的为局部变量;
二、加var为局部变量(在方法内),不加var为全局变量(当方法内有一次使用后)。
在写jquery plugin的时候,不小心没加var 声明变量(比如option),导致成为全局变量,多个容器同时初始化组件的时候,
所有容器的option都变成了最后渲染的容器的option,于是各种蛋疼诡异的事情就发生了。
15、datagrid数据和json定制数据合并
场景:easyui-datagrid组件获取到原始数据,根据datagrid中的几个field属性的值作为定位某行的索引,根据这个索引去json定制数据中取值合并。
核心算法:
function combineDataGrid(dataJson,paramJson,indexKeys){// indexKeys 索引fields,数组:['field1','field2'...] var rows = dataJson.rows; $.each(rows,function(index,item){ var keyIndex = ''; $.each(indexKeys,function(index,value){ if(index == 0) keyIndex += item[value]; else keyIndex += ','+item[value]; }); if(paramJson[keyIndex] && typeof paramJson[keyIndex] =="object") item = $.extend(item,paramJson[keyIndex]); }); return dataJson; }
demo【jsp】:
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <!-- Bootstrap core CSS --> <link href="<%=request.getContextPath() %>/js/bootstrap/css/bootstrap.min.css" rel="stylesheet"> </head> <body> <div class="contener"> <div class="row"> <div class="col-sm-6"> <div class="panel panel-default"> <div class="panel-heading"> dataGrid 数据 </div> <div class="panel-body"> var dataJson = {"total":28,"rows":[ <br> {"productid":"FI-SW-01","productname":"Koi"},<br> {"productid":"K9-DL-01","productname":"Dalmation"},<br> {"productid":"RP-SN-01","productname":"Rattlesnake"},<br> {"productid":"RP-SN-01","productname":"Rattlesnake"},<br> {"productid":"RP-LI-02","productname":"Iguana"}<br> ]} </div> </div> </div> <div class="col-sm-6"> <div class="panel panel-default"> <div class="panel-heading"> 要合并的属性 </div> <div class="panel-body"> var paramJson = {<br> 'FI-SW-01,Koi':{name:'tomy',address:'北京海淀'},<br> 'RP-SN-01,Rattlesnake':{age: 21},<br> 'RP-LI-02,Iguana':{sex:'男'}<br> }; </div> </div> </div> </div> <div class="row"> <div class="col-sm-12"> <div class="panel panel-default"> <div class="panel-heading"> 合并后结果 </div> <div class="panel-body"> <p id="result"></p> </div> </div> </div> </div> </div> </body> <script src="<%=request.getContextPath()%>/js/jquery/jquery-1.8.3.js"></script> <script src="<%=request.getContextPath() %>/js/bootstrap/js/bootstrap.min.js"></script> <script type="text/javascript"> var dataJson = {"total":28,"rows":[ {"productid":"FI-SW-01","productname":"Koi"}, {"productid":"K9-DL-01","productname":"Dalmation"}, {"productid":"RP-SN-01","productname":"Rattlesnake"}, {"productid":"RP-SN-01","productname":"Rattlesn"}, {"productid":"RP-LI-02","productname":"Iguana"} ]}; var paramJson = {'FI-SW-01,Koi':{productname:'tomy',address:'北京海淀'}, 'RP-SN-01,Rattlesnake':{age: 21}, 'RP-LI-02,Iguana':{sex:'男'}}; var indexKeys = ['productid','productname']; function combineDataGrid(dataJson,paramJson,indexKeys){ var rows = dataJson.rows; $.each(rows,function(index,item){ var keyIndex = ''; $.each(indexKeys,function(index,value){ if(index == 0) keyIndex += item[value]; else keyIndex += ','+item[value]; }); if(paramJson[keyIndex] && typeof paramJson[keyIndex] =="object") item = $.extend(item,paramJson[keyIndex]); }); return dataJson; } combineDataGrid(dataJson,paramJson,indexKeys); $("#result").append('var dataJson = {"total":28,"rows":['); $.each(dataJson.rows,function(index,item){ $("#result").append('<br>' +JSON.stringify(item)); }); $("#result").append('<br>]}'); </script> </html>
效果:
16、页面多级嵌套iframe超时登出,整体登出处理
不正常情况:(正确应该是整个首页都应该跳到登陆界面)
处理方法:(在登陆页面加入如下脚本)
<script type="text/JavaScript"> var b = window.top!=window.self; // 是否和顶级窗口同级 if(b) window.top.logoutSys(); // 调用顶级窗口的登出方法 </script>
17、js实现文件下载
// url方式
function downloadFile(url) { try{ var elemIF = document.createElement("iframe"); elemIF.src = url; elemIF.style.display = "none"; document.body.appendChild(elemIF); }catch(e){ } }
// 表单提交返回数据方式
function downloadFile(url, paramsInput) { var formStr = null,hideIfm=null; $("body").find("form[target='hideIframe']").remove(); $("body").find("iframe[name='hideIframe']").remove(); formStr = $('<form style="visibility:hidden;" target="hideIframe" method="POST" action="' + url + '">'
+ '<input type="hidden" name="op" value="' + paramsInput.op + '" />'
+ '<input type="hidden" name="name" value="' + paramsInput.name + '" />' + '<input type="hidden" name="params" value="' + paramsInput.params + '" />'
+ '</form>'); hideIfm = $("<iframe name='hideIframe'></iframe>").hide(); $("body").append(hideIfm); $("body").append(formStr); formStr.get(0).submit(); }
18、js监测系统信息(32位、64位)及监测浏览器版本
function getCPU(){ var agent=navigator.userAgent.toLowerCase(); if(agent.indexOf("win64")>=0||agent.indexOf("wow64")>=0) return "x64"; return navigator.cpuClass;
}
<script type="text/javascript"> var userAgent = navigator.userAgent, rMsie = /(msie\s|trident.*rv:)([\w.]+)/, rFirefox = /(firefox)\/([\w.]+)/, rOpera = /(opera).+version\/([\w.]+)/, rChrome = /(chrome)\/([\w.]+)/, rSafari = /version\/([\w.]+).*(safari)/; var browser; var version; var ua = userAgent.toLowerCase(); function uaMatch(ua){ var match = rMsie.exec(ua); if(match != null){ return { browser : "IE", version : match[2] || "0" }; } var match = rFirefox.exec(ua); if (match != null) { return { browser : match[1] || "", version : match[2] || "0" }; } var match = rOpera.exec(ua); if (match != null) { return { browser : match[1] || "", version : match[2] || "0" }; } var match = rChrome.exec(ua); if (match != null) { return { browser : match[1] || "", version : match[2] || "0" }; } var match = rSafari.exec(ua); if (match != null) { return { browser : match[2] || "", version : match[1] || "0" }; } if (match != null) { return { browser : "", version : "0" }; } } var browserMatch = uaMatch(userAgent.toLowerCase()); if (browserMatch.browser){ browser = browserMatch.browser; version = browserMatch.version; } document.write(browser+version); </script>
19、jquery html方法失效问题(ie8 及以下)
今天遇到jquery中的html方法使用不了,只能用完最基本的innerHTML把内容展示出来。具体原因还没找到,肯定跟内容有关
$("#content").html(data.content); // ie8及以下情况下异常
$("#content")[0].innerHTML = data.content;
下面是其它网友的补充:
jQuery一般来说还是很好用的,但有时候它也会有些问题的,比如jQuery的html()方法设置html代码,在一种情况下,ie6、ie7、ie8 下是不能设置html代码的。本文说的问题只针对ie8(包括ie8)以下的浏览器。
1.什么情况下IE6、IE7、IE8 jQuery.html("xxx")方法会设置不上html代码?
答:当被加载的的html代码里面出现以下情况,ie8(包括ie8)以下是设置不上html代码的:
a) 被设置的html代码中包含引用其他js的,如:<script src="Stone.js" type="text/javascript"></script> 这种情况下,设置html代码无效。
b) 被设置的html代码中包含js 方法的,如:function Stone(){ alert("我叫MT"); },设置html代码无效。
c) 被设置的html代码中有css 样式的,如:.Stone ul li{ list-style:none;float:left; }等,设置的html代码无效。[附加:被设置的html代码中如果包含引用其他外部
样式的,比如:<link href="../Css/style.css" rel="stylesheet" type="text/css" />,虽然不会影响html设置,但是被引用的css是无效的,是没有样式的。]
2.原因分析:
答:被设置的html,jQuery只是单纯的解析为html,不会去理会其他的因素和代码,所有导致上述问题的出现。
3.解决方案:
答:去掉被设置的js引用css引用和代码即可解决。
20、Ajax中window.location.href无法跳转的解决办法
$.ajax({ //async:false, //设置ajax的同步 type: "get", //get方式 url: "../handler/QueryQuestionnaire.ashx", //返回数据成功,将返回的json数据解析,显示在课程信息列表中 success: function (strJson) { //检查后台返回的数据 var dataArray = eval(strJson); window.location.href = url;//要访问的网址 }, //返回数据失败,弹出错误显示 error: function (XmlHttpRequest, textStatus, errorThrown) { alert(XmlHttpRequest.responseText); } });
return false;
一般情况下要加上:return false
21、事件绑定匿名函数变量传参问题
function uploadFile(ob,cnt) { var url = getUrl(ob); if(ob.files){ for(var i=0;i<ob.files.length;i++){ var uidRan = Math.round(Math.random()*10000000000);//改成const uiRan申明方式(常量)var fd = new FormData(); fd.append("fileInput", ob.files[i]); var xhr = new XMLHttpRequest(); xhr.upload.addEventListener("progress", function(){ console.info("传入的值:"+uidRan); //uploadProgress(event,cnt,{uid:uidRan}); }, false); console.info(uidRan); xhr.addEventListener("load", uploadComplete, false); xhr.addEventListener("error", function(){uploadFailed(event,cnt);}, false); xhr.addEventListener("abort", uploadCanceled, false); xhr.open("POST", url);//修改为自己服务器接口地址 xhr.send(fd); } } }
改成const uidRan = Math.round(Math.random()*10000000000);申明后正常
22、复制文本到剪切板
核心js:(亲测ie google兼容,其他没有测试)
function copyText(text){ var textCtner = document.createElement("div"); textCtner.innerHTML = text; var txt = textCtner.innerText;//之所以中间转换,防止text中有dom格式的文本,会导致textarea.innerHTML设置失效 var textarea = document.createElement("textarea"); textarea.innerHTML = txt; document.body.appendChild(textarea); textarea.select(); // 选择对象 document.execCommand("Copy"); // 执行浏览器复制命令 document.body.removeChild(textarea); }
23、radio之trgger触发事件问题
dom容器:
<div class="inputRadio" data-option="{changeInput:'changeEvt()'}"></div> <button onclick="clickEvt()">trgger</button>
脚本:
<script type="text/javascript"> function changeEvt(){ alert(1); } function clickEvt(){ $("input[name='age'][value='0']").attr("checked",true); $("input[name='age'][value='0']").trigger("click"); } (function ($) { $.fn.inputRadio = function (op) { return this.each(function(){ var changeInput = eval("(" + $(this).attr("data-option") + ")").changeInput; var id = $(this).attr("id"); var txt = $(this), strHtml = '<input type="radio" name="age" value="1" "/>是'+ '<input type="radio" name="age" value="0" "/>否'; txt.after(strHtml); txt.remove(); $('input[name="age"]').bind("click", function(){ var nameA = $(this).attr("name"); if(changeInput){ eval(changeInput); } }); }); }; })(jQuery); $(".inputRadio").inputRadio(); </script>
会发现点击按钮时,先执行changeEvt()方法,然后才选中目标,这样就会造成无法及时获取选中的值。
改进changeEvt():
function clickEvt(){ $("input[name='age'][value='0']").attr("checked",true); setTimeout(function(){ $("input[name='age'][value='0']").trigger("click"); },0); }
如此便能及时获取到选中的值
24、js文件中使用EL表达式方案
如果js非要放入单独文件中,可以把js文件命名为.jsp文件就可以了,这样里面el就能运行,也就是服务器可以执行这个文件了。无非页面引用的时候引用jsp就可以了。
<script src="myjs.jsp" type="text/javascript> </script>
25、计算容器剩余高度
在开发table组件时,实现表格高度依据父容器动态计算,需要将可见元素的高度都减除掉,代码逻辑如下:
<script> const SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g; const MOZ_HACK_REGEXP = /^moz([A-Z])/;function _usableHeight(node){ let parentNode = node.parentNode, firstNode = parentNode.firstElementChild, lastNode = parentNode.lastElementChild, nextNode = node.nextElementSibling, usableHeight = parentNode.clientHeight;//parseInt(getStyle(parentNode, 'height')); //let tbHeight = usableHeight*(this.height.replace('%','')-0)/100; /* reduce height of other visible doms */ let fistMarginTop = parseInt(getStyle(firstNode, 'margin-top'))||0, fistTop = parseInt(getStyle(firstNode, 'top'))||0; usableHeight -= node.offsetTop - firstNode.offsetTop + fistMarginTop + fistTop; if(lastNode != node){ let nextMarginTop = parseInt(getStyle(nextNode, 'margin-top'))||0, nextTop = parseInt(getStyle(nextNode, 'top'))||0, lastMarginBottom = parseInt(getStyle(lastNode, 'margin-bottom'))||0, lastBottom = parseInt(getStyle(lastNode, 'bottom'))||0; var lastBth = lastNode.offsetTop - nextNode.offsetTop + lastNode.offsetHeight + nextMarginTop + nextTop + lastMarginBottom + lastBottom; usableHeight -= lastBth; } let nodeMarginBottom = parseInt(getStyle(node, 'margin-bottom')) ||0, nodeBottom = parseInt(getStyle(node, 'margin-bottom'))||0; usableHeight -= node.offsetHeight + nodeMarginBottom + nodeBottom;//parseInt(getStyle(node, 'height'));return usableHeight; } function camelCase(name) { return name.replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) { return offset ? letter.toUpperCase() : letter; }).replace(MOZ_HACK_REGEXP, 'Moz$1'); } function getStyle(element, styleName) { if (!element || !styleName) return null; styleName = camelCase(styleName); if (styleName === 'float') { styleName = 'cssFloat'; } try { const computed = document.defaultView.getComputedStyle(element, ''); return element.style[styleName] || computed ? computed[styleName] : null; } catch (e) { return element.style[styleName]; } } </script>
注意: nextSibling、lastChild,IE将跳过在节点之间产生的空格文档节点(如:换行字符),而Mozilla不会这样——FF会把诸如空格换行之类的排版元素视作节点读取,因此,在ie 中用nextSibling便可读取到的下一个节点元素,在FF中就需要这样写:nextElementSibling了。
26、禁用浏览器回退
// 禁止浏览器回退
history.pushState(null, null, document.URL); window.addEventListener('popstate', function () { history.pushState(null, null, document.URL); });