背景:
遗留项目中用了 dwr 1.1 ,修 bug 看了看 DWRUtil.useLoadingMessage 有问题,修正后再看 dwr 2.0 ,3.0 rc1的 useLoadingMessage 实现,也不是很完美,改进下
dwr:
在 ajax 应用中,在同服务器通信的同时显示当前运行状态,可以达到很好的用户体验,如 经典的 Gmail loading :
dwr 作为整合后端的 ajax 框架,很早的就考虑到了这个问题,提供了useLoadingMessage ( 底层依靠prehook 与 posthook ) 使得用户可以介入 xhr 请求的发送过程中去,这个机制对所有的请求统一考虑,可以一次设置,每次请求都应用。但是dwr 的实现不是很完美。
dwr 1.1
function(message) { var loadingMessage; if (message) { loadingMessage = message; } else { loadingMessage = "Loading"; } DWREngine.setPreHook(function() { var disabledZone = $("disabledZone"); if (!disabledZone) { disabledZone = document.createElement("div"); disabledZone.setAttribute("id", "disabledZone"); disabledZone.style.position = "absolute"; disabledZone.style.zIndex = "1000"; disabledZone.style.left = "0px"; disabledZone.style.top = "0px"; disabledZone.style.width = "100%"; disabledZone.style.height = "100%"; document.body.appendChild(disabledZone); var messageZone = document.createElement("div"); messageZone.setAttribute("id", "messageZone"); messageZone.style.position = "absolute"; messageZone.style.top = "0px"; messageZone.style.right = "0px"; messageZone.style.background = "red"; messageZone.style.color = "white"; messageZone.style.fontFamily = "Arial,Helvetica,sans-serif"; messageZone.style.padding = "4px"; disabledZone.appendChild(messageZone); var text = document.createTextNode(loadingMessage); messageZone.appendChild(text); } else { $("messageZone").innerHTML = loadingMessage; disabledZone.style.visibility = "visible"; } }); DWREngine.setPostHook(function() { $("disabledZone").style.visibility = "hidden"; }); }
问题:
1.disableZone ie 下百分比大小不能正常设置
2.当多个同时请求发生时,当一个请求返回则 loadingMessage 就被 hidden ,而其实后面的请求还没回来,当前总体状态应为 loading 。
dwr 2.0
function(message) { var loadingMessage; if (message) { loadingMessage = message; } else { loadingMessage = "Loading"; } dwr.engine.setPreHook(function() { var disabledZone = dwr.util.byId("disabledZone"); if (!disabledZone) { disabledZone = document.createElement("div"); disabledZone.setAttribute("id", "disabledZone"); disabledZone.style.position = "absolute"; disabledZone.style.zIndex = "1000"; disabledZone.style.left = "0px"; disabledZone.style.top = "0px"; disabledZone.style.width = "100%"; disabledZone.style.height = "100%"; document.body.appendChild(disabledZone); var messageZone = document.createElement("div"); messageZone.setAttribute("id", "messageZone"); messageZone.style.position = "absolute"; messageZone.style.top = "0px"; messageZone.style.right = "0px"; messageZone.style.background = "red"; messageZone.style.color = "white"; messageZone.style.fontFamily = "Arial,Helvetica,sans-serif"; messageZone.style.padding = "4px"; disabledZone.appendChild(messageZone); var text = document.createTextNode(loadingMessage); messageZone.appendChild(text); dwr.util._disabledZoneUseCount = 1; } else { dwr.util.byId("messageZone").innerHTML = loadingMessage; disabledZone.style.visibility = "visible"; dwr.util._disabledZoneUseCount++; } }); dwr.engine.setPostHook(function() { dwr.util._disabledZoneUseCount--; if (dwr.util._disabledZoneUseCount == 0) { dwr.util.byId("disabledZone").style.visibility = "hidden"; } }); }
新增了一个属性 _disabledZoneUseCount 记录了当前还没处理完毕的请求个数,只有在所有请求处理完毕后才隐藏 loadingMessage 。
问题:
1.disableZone ie 下百分比大小不能正常设置
2.loadingMessage 定位为absolute ,当页面很长出现滚动条时,则当用户在页面底部操作时会出现loadingMessage 仍在文档顶部窗口之外的现象,合适的做法应该是用 fixed 定位,但是 ie6 不支持,但对ie6合适的做法应为 绝对定位到 scrollTop 坐标处即可。
dwr 3.0 rc1 基本等同 dwr 2.0
function(message) { var loadingMessage; if (message) { loadingMessage = message; } else { loadingMessage = "Loading"; } dwr.engine.setPreHook(function() { var disabledZone = dwr.util.byId("disabledZone"); if (!disabledZone) { disabledZone = document.createElement("div"); disabledZone.setAttribute("id", "disabledZone"); disabledZone.style.position = "absolute"; disabledZone.style.zIndex = "1000"; disabledZone.style.left = "0px"; disabledZone.style.top = "0px"; disabledZone.style.width = "100%"; disabledZone.style.height = "100%"; if (window.ActiveXObject) { disabledZone.style.background = "white"; disabledZone.style.filter = "alpha(opacity=0)"; } document.body.appendChild(disabledZone); var messageZone = document.createElement("div"); messageZone.setAttribute("id", "messageZone"); messageZone.style.position = "absolute"; messageZone.style.top = "0px"; messageZone.style.right = "0px"; messageZone.style.background = "red"; messageZone.style.color = "white"; messageZone.style.fontFamily = "Arial,Helvetica,sans-serif"; messageZone.style.padding = "4px"; document.body.appendChild(messageZone); var text = document.createTextNode(loadingMessage); messageZone.appendChild(text); dwr.util._disabledZoneUseCount = 1; } else { dwr.util.byId("messageZone").innerHTML = loadingMessage; disabledZone.style.visibility = "visible"; dwr.util._disabledZoneUseCount++; dwr.util.byId("messageZone").style.visibility = "visible"; } }); dwr.engine.setPostHook(function() { dwr.util._disabledZoneUseCount--; if (dwr.util._disabledZoneUseCount == 0) { dwr.util.byId("disabledZone").style.visibility = "hidden"; dwr.util.byId("messageZone").style.visibility = "hidden"; } }); }
我的改进:
可用闭包将当前active的请求封在小作用域内,判断ie6 绝对定位到scrollTop,而对于高级浏览器则直接fixed定位,另外 ie disableZone 百分比大小不起作用,改做每次都算一下,完美解决:
(function(){ var ua = navigator.userAgent.toLowerCase(); //judge ie6 var isIE6=/msie 6/.test(ua); // number of activeRequests var activeRequests=0; //disable zone var disabledZone; //loading message zone var messageZone DWRUtil.useLoadingMessage = function(message) { var loadingMessage; if (message) { loadingMessage = message; } else { loadingMessage = "Loading"; } DWREngine.setPreHook(function() { var fixTop=(isIE6?(document.documentElement.scrollTop || (document.body.scrollTop || 0)):0)+"px"; var fixWidth=(document.documentElement.scrollWidth || (document.body.scrollWidth || 0))+"px"; var fixHeight=(document.documentElement.scrollHeight || (document.body.scrollHeight || 0))+"px"; if (!disabledZone) { disabledZone = document.createElement("div"); disabledZone.setAttribute("id", "disabledZone"); disabledZone.style.position = "absolute"; disabledZone.style.zIndex = "10001"; disabledZone.style.left = "0px"; disabledZone.style.top = "0px"; //ie 100% can not work disabledZone.style.width = fixWidth; disabledZone.style.height = fixHeight; //ie opacity if (window.ActiveXObject) { disabledZone.style.background = "#cccccc"; disabledZone.style.filter = "alpha(opacity=30)"; } document.body.appendChild(disabledZone); messageZone = document.createElement("div"); messageZone.setAttribute("id", "messageZone"); if(isIE6) { messageZone.style.position = "absolute"; } else { messageZone.style.position = "fixed"; } messageZone.style.top = fixTop; messageZone.style.right = "0px"; messageZone.style.background = "red"; messageZone.style.color = "white"; messageZone.style.fontFamily = "Arial,Helvetica,sans-serif"; messageZone.style.padding = "4px"; document.body.appendChild(messageZone); var text = document.createTextNode(loadingMessage); messageZone.appendChild(text); } else { disabledZone.style.width = fixWidth; disabledZone.style.height = fixHeight; messageZone.style.top = fixTop; messageZone.innerHTML = loadingMessage; disabledZone.style.visibility = "visible"; messageZone.style.visibility = "visible"; } ++activeRequests; }); DWREngine.setPostHook(function() { --activeRequests; if(!activeRequests) { disabledZone.style.visibility = "hidden"; messageZone.style.visibility = "hidden"; } }); }; })();