<html>
<head>
<script src="JSLogger.js" charset="UTF-8" config="width:500px;" debug="true"></script>
</head>
<body id="mybody">
<input type="text" id="txt_log" value="请输入log内容"/>
<input type="button" value="添加log" onclick="JSLogger.log(txt_log.value)" >
<!--测试js-->
<script>
//打印存文本
JSLogger.log("启动正常");
//打印原生态html
JSLogger.logHTML("<div style='color:red;'>你好</div>");
//打印带有地址的信息:自动添加超链接
JSLogger.logURL("百度的地址是:http://www.baidu.com");
//打印js对象
var user={Name:"ab",Age:23,Teacher:{Name:"王老师",Grand:"4年纪"},Addrss:"北京市",School:{Name:"育新中雪",Address:"北京市海淀区30号",Tel:null}};
JSLogger.log(user);
//打印表单对象:
JSLogger.log(document.getElementById("txt_log"));
</script>
</body>
</html>
//2012.09.21 更新:
/*1.补充log方法,实现自动判断并打印XMLDOM对象。
2.增加logXML方法,可以打印XML文档对象的全部内容,包括:子节点名称和节点的值,子节点的所有属性以及XML文档的所有数值。
3.新增获取客户单信息的方法。大致包括: 客户端浏览器的类型,版本(version); 分辨率大小,当前窗口大小; IP、端口、web工程名称。
4.完善initError方法。
5.给window扩充log方法(实现JSLogger.log方法的简写)。
6.样式完善等。
对应rar包:JS操作XMLDOM.rar */
组件背景:
在项目开发工程中,经常要监控某一个变量的值,通常的情况下我们都使用alert弹出变量的值,但问题是发布的时候还需要逐个删除alert或者注释(我多半采取注释方法,方便再次使用),而随后还可能对发布的版本进行维护,可能还需要追踪变量的值,这样就再次使用alert。如此反复无常是人头疼。
JSLogger就是解决这个问题的。
主要用途:
1 用于打印信息。可用于记录变量值以及追踪多个方法的先后运行顺序。
特点:
1 是否追踪日志可配置。
2 IE,ff,chrome兼容。
3 log面板可关闭/打开,以及实时清空日志。
新增1:对象型数据记录log:打印一个Object类型数据Obj的属性。如果Obj的属性P仍是Object,继续打印P的所有属性。(只向下打印到二级属性,即对象.属性.属性)
新增2:打印DOM对象,并且属性按照A-Z,a-z排序。(IE不兼容,在chrome和ff下正常)
源码实例:
//alert("JSLogger"); var JSLogger=function(){ this.divdom =document.createElement("div");//日志div的对象。 return{ init:function(){//初始化调试信息。 var logObj = this; if(JSLogger.debug()==true){ divdom.id="log_div_";//日志div的ID divdom.style.border="0px solid gray";/*边框颜不可变*/ divdom.style.padding="0px";/*不可变*/ divdom.style.fontFamily="Arial";/*字体可变*/ divdom.style.margin="0px";/*不可变*/ divdom.style.background="white";/*可变*/ divdom.style.width=(logObj.config.width || "300px");/*宽度可变*/ divdom.style.height=(logObj.config.height || "300px");/*高度可变*/ divdom.style.position="absolute";/*不可变*/ divdom.style.fontSize="14";/*不可变*/ divdom.style.textAlign="left";/*不可变*/ divdom.style.zIndex=(9999*9999);/*控制日志组件在所有可用组件的上边*/ if(!!logObj.config.top===true ){ divdom.style.top = (parseInt(logObj.config.top) ||0)+"px"; }else{ divdom.style.bottom="0";/*不可变*/ } var titleHTML = ""; //左下角还是右下角 if(typeof(logObj.config.pos)==="string" && (logObj.config.pos==="left")){ divdom.style.left="0";/*不可变*/ titleHTML = logObj.createTitle({}); }else{ divdom.style.right="0";/*不可变*/ titleHTML = logObj.createTitle({}); } divdom.style.overflow="hidden";/*不可变 不出现滚动条的关键。*/ divdom.style.cursor="pointer";/*光标样式不可变*/ divdom.innerHTML=titleHTML; document.body.appendChild(divdom); if(logObj.config.closed=="true"){ logObj.hide(logObj.getById("close_open_label")); } }else{/*do nothing*/} }, createTitle:function(config){//显示关闭和清除的div //var align = (typeof(config.align)==="string" && "left"===config.align)?"left":"right";//默认右下角 var html = '<div style="text-align:right;background:red;overflow:hidden;height:20px;">' //关闭和打开按钮 +'<font style="color:white;cursor:pointer ;" onselectstart="return false" id="close_open_label" state="true" onmouseout="this.style.fontWeight=\'\'" onmouseover="this.style.fontWeight=\'bold\'" onclick="JSLogger.hide(this)">Close</font>' +' <font style="color:white;cursor:pointer;" onselectstart="return false" state="true" title="clear log message" onmouseout="this.style.fontWeight=\'\';" onmouseover="this.style.fontWeight=\'bold\'" onclick="JSLogger.clear()">Clear</font>' +'</div>' +'<div id="log_div_msg" style="background:white;border:1px solid red;width:100%;height:95%;overflow:auto;"></div>';//log_div_msg 用于加载日志信息。 //+'<div style="background:white;border:1px solid red;width:100%;height:100px;">END</div>'; return html; }, clear:function(){//清空log信息 this.getById("log_div_msg").innerHTML=""; }, hide:function(ADom){//隐藏和显示调试信息。 var logObj = this; var state = ADom.getAttribute("state"); if(state=="true"){ divdom.style.width="32px"; divdom.style.height="20px"; divdom.style.background="red"; ADom.setAttribute("state","false"); logObj.getById("log_div_msg").style.display="none"; logObj.getById("close_open_label").innerHTML="Open"; }else{ divdom.style.background=""; divdom.style.height=(logObj.config.height || "300px"); divdom.style.width=(logObj.config.width || "300px");/*宽度可变*/ ADom.setAttribute("state","true"); logObj.getById("log_div_msg").style.display=""; logObj.getById("close_open_label").innerHTML="Close"; } }, debug:function(){//看是否启用调试 var logObj = this; var arr = document.getElementsByTagName("script");//.concat(top.document.getElementsByTagName("script")); var res=false; for(var i=0;i<arr.length;i++){ var src = arr[i].getAttribute("src"); if(null!=src){ if(src.indexOf("/JSLogger.js")>=0 || "JSLogger.js"==src){ var flag = arr[i].getAttribute("debug"); if("true"==flag){ //config="width=500px;open=true;" var config = arr[i].getAttribute("config") || ""; if(!!config===true){ logObj.config = logObj.toJSON(config); } res=true; break; } } } } //logObj.debug = function(){return res;} return res; }, toJSON:function(str){ var json = {}; str = str.replace(/,/g,";");//兼容使用;号 和 使用,号进行JSON标记 var arr = str.split(";"); for(var i=0;i<arr.length;i++){ var v= arr[i].split(":"); if(!!arr[i]===false ||v.length!=2 ){ continue; } json[v[0]] = v[1]; } return json; }, loadLog:function(){//加载完毕后执行的方法 var logObj = this; if(window.attachEvent){ document.onreadystatechange = function(){ if(document.readyState=="complete"){ logObj.init(); //alert('IE浏览器加载完毕'); } } }else{ document.addEventListener("DOMContentLoaded",function(){ logObj.init(); //alert("火狐浏览器加载完毕"); },false); } },sort:function(dom){ var arr = []; for(var i in dom){ arr.push(i); } return arr.sort(); },logHTML:function(ahtml){ var logObj = this; var v = ahtml.replace(/</g,"<").replace(/>/g,">"); logObj.log(v); },logURL:function(ahtml){ var logObj = this; var url = ahtml; var before = url.replace(/https{0,1}:\/\/.{1,}/,""); var _url = url.split(before)[1]; var v = _url.replace(/</g,"<").replace(/>/g,">") var res = before+"<a href="+v+" target='_blank'>"+v+"</a>"; logObj.log(res); }, logXML:function(xmlDOM){//打印XML文档对象的全部文本内容 var logObj = this; logObj.logHTML(logObj.getXML(xmlDOM.childNodes[0])); }, getXML:function(xmlDOM){//循环获取XML对象中的属性和值 var logObj = this; var v =""; var firstChild = xmlDOM; while(firstChild!=null){ //log(firstChild.nodeName); if("#comment"==firstChild.nodeName){ v += ("<--"+firstChild.nodeValue+"-->"); firstChild = firstChild.nextSibling; continue; } v += ("<"+firstChild.nodeName+""); var attr = firstChild.attributes||[]; if(attr.length>0){ for(var j=0;j<attr.length;j++){ v +=(" "+attr[0].nodeName+"= \""+attr[0].nodeValue+"\""); } } for(var j=0;j<attr.length;j++){ v += (attr[j]); } v +=">"; //log(firstChild.firstChild.nodeName); if("#text"!=firstChild.firstChild.nodeName){ var sonFirstChild = firstChild.childNodes[0]; v += logObj.getXML(sonFirstChild); }else{ v += (firstChild.childNodes[0].nodeValue); } v += ("</"+firstChild.nodeName+">"); firstChild = firstChild.nextSibling; } return v; }, getXMLJSON:function(xmlDOM){//获取XML DOM对象的结构 //JSLogger.log("xmlDOM.nodeName = "+xmlDOM.nodeName); var arr = []; if("#document"!=xmlDOM.nodeName){ //根节点属性 var attr = xmlDOM.attributes||[]; var _v = ""; if(attr.length>0){ _v = "["; for(var j=0;j<attr.length;j++){ _v +=(""+attr[0].nodeName+"= \""+attr[0].nodeValue+"\" "); } _v += "]"; } arr.push("+"+ xmlDOM.nodeName+_v+":【XMLDOM】"+"<br/>");//根节点属性END //根节点所有子节点 var childs = xmlDOM.childNodes; for(var i=0;i<childs.length;i++){ if(childs[i].nodeType==1){//其他节点不打印 var first = childs[i]; var attr = first.attributes||[];//子节点属性 _v = ""; //子节点属性 if(attr.length>0){ _v = "["; for(var j=0;j<attr.length;j++){ _v +=(" "+attr[0].nodeName+"= \""+attr[0].nodeValue+"\""); } _v += "]"; } //自己点的值 if( "#text" == first.firstChild.nodeName){//没有子节点 arr.push("--"+first.nodeName+_v+"="+first.firstChild.nodeValue+"<br/>"); }else{ arr.push("--"+first.nodeName+_v+"=【XMLDOM】0="+first.firstChild.nodeName+"<br/>"); } //arr.push("--"+ childs[i].nodeName+":"+childs[i].childNodes[0].nodeValue+"<br/>"); } } arr.sort(); return arr.join(""); } var childs = xmlDOM.childNodes; var len = childs.length; for(var i=0;i<len;i++){ var first = childs[0].firstChild; var attr = childs[0].attributes||[]; var _v = ""; if(attr.length>0){ _v = "["; for(var j=0;j<attr.length;j++){ _v +=(""+attr[0].nodeName+"= \""+attr[0].nodeValue+"\" "); } _v += "]"; } arr.push("+"+ childs[0].nodeName+_v+":【XMLDOM】"+"<br/>"); while(first!=null){ //JSLogger.log(first.nodeType); if( first.nodeType!=1){//只要有效类型的节点 first = first.nextSibling; continue; } attr = first.attributes ||[]; _v = ""; if(attr.length>0){ _v = "["; for(var j=0;j<attr.length;j++){ _v +=(" "+attr[0].nodeName+"= \""+attr[0].nodeValue+"\""); } _v += "]"; } if( "#text" == first.firstChild.nodeName){//没有子节点 arr.push("--"+first.nodeName+_v+"="+first.firstChild.nodeValue+"<br/>"); }else{ arr.push("--"+first.nodeName+_v+"=【XMLDOM】<br/>"); } first = first.nextSibling; } } arr.sort(); return arr.join(""); },logColor:function(text,color){ var logObj = this; color = color || ""; logObj.log("<div style='color:"+color+"'>"+text+"</div>"); },getById:function(id){ return document.getElementById(id); },error:function(v){ var logObj = this; logObj.log("<span style='color:red'>【error】</span>"+v+""); logObj.getById("close_open_label").innerHTML="<span id='log_error_span'>Error</span>"; var span = logObj.getById("log_error_span").parentNode.parentNode; var counter = 0,preBgColor = span.style.backgroundColor ; var logInterval = setInterval(function(){ if((counter++)%2==0){ span.style.backgroundColor = "yellow"; }else{span.style.backgroundColor = "red"; } },100); setTimeout(function(){ clearInterval(logInterval); span.style.backgroundColor = preBgColor; },5000); },log:function(msg,s_b,s_likeV){//msg 打印的信息或者对象,likeV属性名称相似的条件,b是否打印对象的子项的内容 var logObj = this; setTimeout(function(){ if(JSLogger.debug()!=true){return;} //if(msg instanceof Object){//记录的信息为对象类型 if(null==msg){msg="null";}//null值处理 var b = (typeof(s_b)=="boolean"?s_b:typeof(s_likeV)==="boolean"?s_likeV:false);//默认为false var likeV = (typeof(s_b)=="string"?s_b:typeof(s_likeV)==="string"?s_likeV:"");//默认为“” likeV = likeV.toLowerCase();//统一转成小写 //alert("b = "+b+",likeV = "+likeV) if( typeof(msg)=='object'){ //alert("对象性数据"); var html="【object】:<br/>"; if(("getAttribute" in msg) && ("innerHTML" in msg)){ //alert("DOM对象") var arr = logObj.sort(msg); html="【object】:共"+arr.length+"属性<br/>"; //alert(arr) for(var i=0;i<arr.length;i++){ var name = arr[i]; //属性条件过滤 if(""!==likeV && name.toLowerCase().indexOf(likeV)==-1){ continue; } var v = msg[name]; //v是字符类型的数据,直接累加。 if(typeof(v)=="function"){ html+=("+"+name+"=【function】<br/>"); continue; } if(typeof(v)=="object"){ html+=("+"+name+"=【object】<br/>"); continue; } if(typeof(v)=="string"){ v = v.replace(/</g,"<").replace(/>/g,">"); } html+=("--"+name+"="+v+"<br/>"); } }else if((typeof msg.childNodes) && ("nodeName" in msg)){//打印XML DOM对象的主体结构 //JSLogger.log("XML DOM对象"); html = logObj.getXMLJSON(msg);//结构 }else{ //JS的Object对象 JSLogger.log("JS对象") var arrPs = logObj.sort(msg); html="【object】:共"+arrPs.length+"属性<br/>"; for(var i=0;i<arrPs.length;i++){ var name = arrPs[i]; //属性条件过滤 if(""!==likeV && name.toLowerCase().indexOf(likeV)==-1){ continue; } var v = msg[name]; if(v!=null && typeof(v)=='object'){ //if(v!=null && (v instanceof Object)){ //v是对象类型的数据,不直接累加。 html+=("+"+name+"=【object】:<br/>"); //加载一级子项。 if(b==true){ for(var sonName in v){ html+=(" --"+sonName+"="+v[sonName]+"<br/>"); } } }else if(v!=null && (typeof(v)=='object'||typeof(v)=='function')){ //加载一级子项。 if(b==true){ html+=("--"+name+"="+v+"<br/>"); }else{ html+=("+"+name+"=【function】:<br/>"); } }else{ //v是字符类型的数据,直接累加。 if(typeof(v)=="string"){ v = v.replace(/</g,"<").replace(/>/g,">"); } html+=("--"+name+"="+v+"<br/>"); } } } logObj.getById("log_div_msg").innerHTML+=("<div style='word-wrap:break-word; word-break:break-all;background:white;list-style:none;padding:0p;margin:0px;border-bottom:1px dotted gray;width:100%;'>"+html+"</div>"); }else{ //msg = msg.replace(/</g,"<").replace(/>/g,">"); logObj.getById("log_div_msg").innerHTML+=("<div style='word-wrap:break-word; word-break:break-all;background:white;list-style:none;padding:0p;margin:0px;border-bottom:1px dotted gray;width:100%;'>"+msg+"</div>"); } },100) }, /* * 报错处理 * **/ initError:function(window){ window.onerror= function(sMessage,sUrl,sLine){ sMessage = sMessage ||""; sUrl = sUrl ||""; sUrl = sUrl.substring(sUrl.lastIndexOf("/")+1,sUrl.length); sLine = sLine||""; var v = (sUrl+"第"+sLine+"行:"+sMessage); if(JSLogger){ JSLogger.logColor(v,"red"); }else if(top.JSLogger){ top.JSLogger.logColor(v,"red"); } return true; } } }//rturn end }(); /* * 工具类获取: * 客户端浏览器的类型,版本(version) * 分辨率大小,当前窗口大小 * IP、端口、web工程名称 * ***/ var ClientInfo ={ /** * 拷贝某一个JSON属性到当前对象 *@param selfJSON 当前JSON对象 *@param targetJSON 即将拷贝的JSON对象 *@param override targetJSON属性是否覆盖selfJSON的属性 **/ copyJSON : function(selfJSON,targetJSON,override){ if(!!selfJSON===false){return {};} targetJSON = targetJSON ||{}; override = typeof(override)?override:true; for(var p in targetJSON){ if(override===true){ selfJSON[p] = targetJSON[p]; }else{ if((p in selfJSON)===false){ selfJSON[p] = targetJSON[p]; } } } }, /** * 拷贝某一个JSON属性到当前对象 *@param selfJSON 当前JSON对象 *@param targetJSON 即将拷贝的JSON对象(如果数组的值是K:V形式,那么K是selfJSON属性显示名称,V是targetJSON属性的名称) *@param propArr 拷贝的属性数组 *@param override targetJSON属性是否覆盖selfJSON的属性 **/ copyPros :function(selfJSON,targetObj,propArr,override){ if(!!selfJSON===false){return {};} targetObj = targetObj ||{}; propArr = propArr ||[]; override = typeof(override)?override:true; for(var i=0;i<propArr.length;i++){ var name = propArr[i].split(":")[0];//属性显示的名称 var p = propArr[i].split(":")[1] ||name;//属性原始名称 if(override===true){ selfJSON[p] = targetObj[p]; }else{ if( ((p in selfJSON)===false) && ((p in targetObj)===true)){ selfJSON[name] = targetObj[p]; } } } }, get:function(){ var JSON = {}; var url2 = window.location.href;//"http://172.16.115.34:8080/exchange/"; var reg=/http:\/\/([^\/:]+)(:[0-9]+)?\/([^\/]+)/gi; var res = reg.test(url2); if(res==true){ ClientInfo.copyJSON(JSON,{server:RegExp.$1,port:RegExp.$2,sitename:RegExp.$3},false); } JSON.href=window.location.href; JSON.isIE = (navigator.userAgent.indexOf("MSIE")>=0); JSON.isFF = (navigator.userAgent.indexOf("Firefox")>=0); JSON.isChrome = (navigator.userAgent.indexOf("Chrome")>=0); if(JSON.isIE){ JSON.version = (navigator.userAgent.split("MSIE")[1]).split(";")[0].replace(/ /,''); } if(JSON.isFF){ JSON.version = (navigator.userAgent.split("Firefox/")[1]); } if(JSON.isChrome){ JSON.version = (navigator.userAgent.split("Chrome/")[1]).split("Safari")[0].replace(/ /,''); } ClientInfo.copyPros(JSON,navigator,['userAgent','platform','language','userLanguage','cookieEnabled'],false); ClientInfo.copyPros(JSON,window.screen,["screenWidth:availWidth","screenHeight:availHeight"],false); ClientInfo.copyPros(JSON,window.document.body,["bodyWidth:clientWidth","bodyHeight:clientHeight"],false); return JSON; } } JSLogger.loadLog(); JSLogger.initError(window); if(typeof(window.log)=="undefined"){ window.log = function(v){ JSLogger.log(v); } } if(typeof(window.logHTML)=="undefined"){ window.logHTML = function(v){ JSLogger.logHTML(v); } }
愤怒的JSER -- 写最干净的日志控件