拦截所有AJAX调用,重点处理服务器异常
背景
上篇文章http://www.cnblogs.com/happyframework/p/3241063.html介绍了如何以AOP的形式处理服务器异常,这让服务器端的编程逻辑变的非常整洁,本文介绍如何在客户端统一处理服务器返回的异常信息。
一点考虑
上篇隐藏了一些概念,即:开发或架构之处,就应当确定哪些异常要返回给UI、哪些异常要写入日志、哪些异常要包装以后返回给UI等等。
AJAX拦截
如何拦截AJAX,不外乎这三种方式:
- 注册全局监听函数。
- 封装一个全局入口。
- 重写或覆盖客户端库的AJAX功能(Javascript是动态语言,可以运行时替换任何东西)。
最简单的莫过于第一种方式,让我们看一下代码:
拦截事件
1 /// <reference path="/ext/ext-all-debug-w-comments.js" /> 2 Ext.define('Tenoner.AjaxMonitor', { 3 singleton: true, 4 requires: ['Ext.Ajax'], 5 6 errorHandlers: [], 7 8 constructor: function () { 9 var me = this; 10 11 Ext.Ajax.timeout = 120000; 12 13 Ext.Ajax.on('requestcomplete', function (connection, response, option) { 14 me.processError(response); 15 }); 16 17 me.callParent(arguments); 18 }, 19 20 addErrorHandler: function (errorHandler) { 21 var me = this; 22 23 me.errorHandlers.push(errorHandler); 24 }, 25 26 processError: function (response) { 27 var me = this; 28 29 var result = Ext.decode(response.responseText); 30 31 if (!result || !result.errorCode) { 32 return; 33 } 34 35 Ext.Array.each(me.errorHandlers, function (errorHandler) { 36 Ext.Object.each(errorHandler, function (errorCode, handler) { 37 if (errorCode == result.errorCode) { 38 handler(); 39 } 40 }); 41 }); 42 } 43 });
注册一个异常拦截方法
1 Tenoner.AjaxMonitor.addErrorHandler({ 2 'CM001': function () { 3 var current = window; 4 5 while (current != current.parent) { 6 current = current.parent; 7 } 8 9 current.location.href = '/Login.htm'; 10 } 11 });
我们还能做哪些?
如果希望自动弹出错误提示,也可以以这种形式处理,这样Javascript代码中也尽可能的是正常的代码。
备注
本文以ExtJs为例,不过思路应当适合所有AJAX框架。
瀑布流效果目前应用很广泛,像花瓣,新浪轻博,蘑菇街,美丽说等好多网站都有.也有好多支持该效果的前段框架,今天学习了一下这种效果的实现,不依赖插件,自己动手分析实现过程,为了便于叙述清楚,分析中的一些名词为自己拟定,不当之处还望见谅.
思路分析
步骤一:构建成行元素 + 寻找新增元素追加位置
瀑布流所有元素的宽度是固定的,我们用浏览器的宽度除以每个瀑布流块的宽度,就是每一行可容纳的瀑布流块的个数.因为,每个瀑布流块的高度不一,我们姑且把组成一行的这组元素称为成行元素,在成行元素放置完毕后,我们如果要再增加一个元素,那么它的位置应该这样找?
“获取成行元素集合中高度最低的那个元素,待放置的元素的top值应该是这个最低元素的高,left值应该是这个最低元素的left值”
这样,新增的这一个元素我们就找到了它存放的位置.这样成行元素中的最低高度值就变为了原来的高度+新增元素的高度.
步骤二:重复步骤一,依赖成行元素追加新元素
步骤一中我们已经实现了一次成行元素追加一个新的元素,这样新元素增加之后我们就构建了新的成行元素,之后的操作就是在新的成行元素中追加新元素,原理同步骤一.
步骤三:实现滚动位置监听,到底部时加载数据
代码实现
实现步骤一描述效果:
实现代码
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>瀑布流效果实现</title>
<script type="text/javascript" src="scripts/jquery-1.8.2.min.js"></script>
<script type="text/javascript" src="scripts/jquery.easydrag.handler.beta2.js"></script>
<script type="text/javascript">
window.onload=function(){
//获取父级对象
var oParent = document.getElementById("main");
//获取父级[第一个参数]下的所有的子元素[按照第二个参数匹配]
var aPin = getClassObject(oParent,"pin");
//获取每一个块的宽度
var iPinW = aPin[0].offsetWidth;
// //计算每行放多少个pin(瀑布流块)页面的宽度/每一个瀑布流块的宽度
var num = Math.floor(document.documentElement.clientWidth/iPinW);
//重置父级的样式,这样保证图片整体居中
oParent.style.cssText="width:" + num*iPinW + "px;margin:0 auto;";
var compareArray = [];
//将一整行的瀑布流块的高度压入一个数组
for (var i = 0; i<num; i++) {
compareArray[i] = aPin[i].offsetHeight;
}
//获取该行瀑布流高度最低的值
var minHeight = Math.min.apply('',compareArray);
//alert(compareArray + ",min=" + minHeight);
//获取改行高度值最小的瀑布流块的索引
var minHkey = getMinHeightKey(compareArray,minHeight);
//为新增的瀑布流块增加样式
aPin[num].style.position = "absolute";
aPin[num].style.top = minHeight + "px";
//设定新增加的瀑布流块的top和left
aPin[num].style.left =aPin[minHkey].offsetLeft + "px";
//将该索引位置的高度改变为新增后的高度[原来瀑布流块的高度+新增的瀑布流块的高度]
compareArray[minHkey] += aPin[num].offsetHeight;
}
/**
* 获取parent下所有样式名为className的对象集合
*/
function getClassObject(parent,className){
var obj = parent.getElementsByTagName("*");
var result = [];
for(var i=0; i<obj.length;i++){
//变量如果匹配className,将匹配的对象放入数组
if(obj[i].className==className){
result.push(obj[i]);
}
}
return result;
}
/**
* 获取arr数组中值为minH的值在数组中的索引
*/
function getMinHeightKey(arr,minH){
for(key in arr){
if(arr[key] == minH){
return key;
}
}
}
</script>
<style type="text/css">
/*设置每一个瀑布流块*/
#main .pin{
width:220px;
height: auto;
padding: 15px 0px 0px 15px; /*上 右 下 左*/
float: left;
}
/*设置每一个瀑布流块中的图像样式*/
#main .pin .box{
width: 200px;
height: auto;
padding: 10px;
background: #FFF;
border: 1px solid #ccc;
box-shadow: 0px 0px 6px #ccc; /*中间投影*/
border-radius: 5px; /*圆角*/
}
#main .pin .box img{
width: 200px;
}
</style>
</head>
<body>
<div id="main">
<!--每一个小块-->
<div class="pin">
<div class="box">
<img src="images/2012110120000859759.jpg">
</div>
</div>
<!--每一个小块-->
<div class="pin">
<div class="box">
<img src="images/2012072300483800466.jpg">
</div>
</div>
<!--每一个小块-->
<div class="pin">
<div class="box">
<img src="images/2012101912011350194.jpg">
</div>
</div>
<!--每一个小块-->
<div class="pin">
<div class="box">
<img src="images/2012102421195356552.jpg">
</div>
</div>
<!--每一个小块-->
<div class="pin">
<div class="box">
<img src="images/2012072312335411883.jpg">
</div>
</div>
<!--每一个小块-->
<div class="pin">
<div class="box">
<img src="images/2012082910221472225.jpg">
</div>
</div>
</div>
</body>
</html>
实现步骤二描述效果
实现代码
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>瀑布流效果实现</title>
<script type="text/javascript" src="scripts/jquery-1.8.2.min.js"></script>
<script type="text/javascript" src="scripts/jquery.easydrag.handler.beta2.js"></script>
<script type="text/javascript">
window.onload=function(){
//获取父级对象
var oParent = document.getElementById("main");
//获取父级[第一个参数]下的所有的子元素[按照第二个参数匹配]
var aPin = getClassObject(oParent,"pin");
//获取每一个块的宽度
var iPinW = aPin[0].offsetWidth;
// //计算每行放多少个pin(瀑布流块)页面的宽度/每一个瀑布流块的宽度
var num = Math.floor(document.documentElement.clientWidth/iPinW);
//重置父级的样式,这样保证图片整体居中
oParent.style.cssText="width:" + num*iPinW + "px;margin:0 auto;";
var compareArray = [];
//遍历获取到的所有瀑布流块
for (var i = 0; i<aPin.length; i++) {
if(i<num){
//成行元素
compareArray[i] = aPin[i].offsetHeight;
}else{
//获取成行元素中高度最低的值
var minHeight = Math.min.apply('',compareArray);
//alert(compareArray + ",min=" + minHeight);
//获取成行元素中高度最低元素的索引
var minHkey = getMinHeightKey(compareArray,minHeight);
//为新增的瀑布流块设置定位
aPin[i].style.position = "absolute";
aPin[i].style.top = minHeight + "px";
//设定新增加的瀑布流块的top和left
aPin[i].style.left =aPin[minHkey].offsetLeft + "px";
//将该索引位置的高度改变为新增后的高度[原来瀑布流块的高度+新增的瀑布流块的高度]
compareArray[minHkey] += aPin[i].offsetHeight;
}
}
}
/**
* 获取parent下所有样式名为className的对象集合
*/
function getClassObject(parent,className){
var obj = parent.getElementsByTagName("*");
var result = [];
for(var i=0; i<obj.length;i++){
//变量如果匹配className,将匹配的对象放入数组
if(obj[i].className==className){
result.push(obj[i]);
}
}
return result;
}
/**
* 获取arr数组中值为minH的值在数组中的索引
*/
function getMinHeightKey(arr,minH){
for(key in arr){
if(arr[key] == minH){
return key;
}
}
}
</script>
<style type="text/css">
/*设置每一个瀑布流块*/
#main .pin{
width:220px;
height: auto;
padding: 15px 0px 0px 15px; /*上 右 下 左*/
float: left;
}
/*设置每一个瀑布流块中的图像样式*/
#main .pin .box{
width: 200px;
height: auto;
padding: 10px;
background: #FFF;
border: 1px solid #ccc;
box-shadow: 0px 0px 6px #ccc; /*中间投影*/
border-radius: 5px; /*圆角*/
}
#main .pin .box img{
width: 200px;
}
</style>
</head>
<body>
<div id="main">
<!--每一个小块-->
<div class="pin">
<div class="box">
<img src="images/2012110120000859759.jpg">
</div>
</div>
<!--每一个小块-->
<div class="pin">
<div class="box">
<img src="images/2012072300483800466.jpg">
</div>
</div>
<!--每一个小块-->
<div class="pin">
<div class="box">
<img src="images/2012101912011350194.jpg">
</div>
</div>
<!--每一个小块-->
<div class="pin">
<div class="box">
<img src="images/2012102421195356552.jpg">
</div>
</div>
<!--每一个小块-->
<div class="pin">
<div class="box">
<img src="images/2012072312335411883.jpg">
</div>
</div>
<!--每一个小块-->
<div class="pin">
<div class="box">
<img src="images/2012082910221472225.jpg">
</div>
</div>
<!--每一个小块-->
<div class="pin">
<div class="box">
<img src="images/2012082910024626515.jpg">
</div>
</div>
</div>
</body>
</html>
会看到新增的瀑布流块在新的成行元素中自动寻找高度最低的那个元素块的相对位置进行追加.添加更多元素查看效果
步骤三:实现滚动到底部时加载数据
该部分没有什么功能,只是检测滚动条的位置距离浏览器底部的相对距离进行数据加载,加载数据时创建对应的瀑布流块.判断相对距离的实现逻辑如下
function checkScrollSite(){
var oParent = document.getElementById("main");
var aPin = getClassObject(oParent,"pin");
//加载数据依赖最后一个瀑布流块变化
var lastPinHeight = aPin[aPin.length-1].offsetTop + Math.floor(aPin[aPin.length-1].offsetHeight/2) ;
var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
//浏览器高度
var documentH = document.documentElement.clientHeight;
if(lastPinHeight<documentH + scrollTop){
//请求数据
return true;
}
return false;
}
在此感谢,郑印在学习上给予的指导.
转载请注明出处:[http://www.cnblogs.com/dennisit/p/3244987.html]
web前端学习笔记-瀑布流的算法分析与代码实现