<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 -- 写最干净的日志控件
JSLogger是一款为了解决项目开发中动态追踪变量值问题的组件,它提供打印信息、错误捕获及客户端信息获取等功能。支持配置是否追踪日志,兼容主流浏览器,并具备关闭/打开日志面板以及实时清空日志的特性。新增功能包括对象型数据深度打印和DOM对象属性排序展示,但在IE下部分功能受限。
4065

被折叠的 条评论
为什么被折叠?



