拦截所有AJAX调用,重点处理服务器异常

背景

上篇文章http://www.cnblogs.com/happyframework/p/3241063.html介绍了如何以AOP的形式处理服务器异常,这让服务器端的编程逻辑变的非常整洁,本文介绍如何在客户端统一处理服务器返回的异常信息。

一点考虑

上篇隐藏了一些概念,即:开发或架构之处,就应当确定哪些异常要返回给UI、哪些异常要写入日志、哪些异常要包装以后返回给UI等等。

AJAX拦截

如何拦截AJAX,不外乎这三种方式:

  1. 注册全局监听函数。
  2. 封装一个全局入口。
  3. 重写或覆盖客户端库的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="data:images/2012110120000859759.jpg">
</div>
</div> <!--每一个小块-->
<div class="pin">
<div class="box">
<img src="data:images/2012072300483800466.jpg">
</div>
</div> <!--每一个小块-->
<div class="pin">
<div class="box">
<img src="data:images/2012101912011350194.jpg">
</div>
</div> <!--每一个小块-->
<div class="pin">
<div class="box">
<img src="data:images/2012102421195356552.jpg">
</div>
</div> <!--每一个小块-->
<div class="pin">
<div class="box">
<img src="data:images/2012072312335411883.jpg">
</div>
</div> <!--每一个小块-->
<div class="pin">
<div class="box">
<img src="data: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="data:images/2012110120000859759.jpg">
</div>
</div> <!--每一个小块-->
<div class="pin">
<div class="box">
<img src="data:images/2012072300483800466.jpg">
</div>
</div> <!--每一个小块-->
<div class="pin">
<div class="box">
<img src="data:images/2012101912011350194.jpg">
</div>
</div> <!--每一个小块-->
<div class="pin">
<div class="box">
<img src="data:images/2012102421195356552.jpg">
</div>
</div> <!--每一个小块-->
<div class="pin">
<div class="box">
<img src="data:images/2012072312335411883.jpg">
</div>
</div> <!--每一个小块-->
<div class="pin">
<div class="box">
<img src="data:images/2012082910221472225.jpg">
</div>
</div> <!--每一个小块-->
<div class="pin">
<div class="box">
<img src="data: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前端学习笔记-瀑布流的算法分析与代码实现

热爱生活,热爱Coding,敢于挑战,用于探索 ...
 
分类: JavaEEWeb前端
标签: 瀑布流

拦截所有AJAX调用,重点处理服务器异常的更多相关文章

  1. Javascript:拦截所有AJAX调用,重点处理服务器异常

    背景 上篇文章http://www.cnblogs.com/happyframework/p/3241063.html介绍了如何以AOP的形式处理服务器异常,这让服务器端的编程逻辑变的非常整洁,本文介 ...

  2. C# 调用Excel 出现服务器出现意外情况. (异常来自 HRESULT:0x80010105 (RPC_E_SERVERFAULT)

    C# 调用Excel 出现服务器出现意外情况. (异常来自 HRESULT:0x80010105 (RPC_E_SERVERFAULT) private Microsoft.Office.Intero ...

  3. 最新升级的火狐38.0.6识别ajax调用返回的""空值可能有异常。

    自已在调用一段ajax开发中,返回的是空值 string result = string.Empty;return result; 但在页面进行$.ajax调用 时 输出alert(result);应 ...

  4. Jquery Ajax调用aspx页面方法

    Jquery Ajax调用aspx页面方法 在asp.net webform开发中,用jQuery ajax传值一般有几种玩法 1)普通玩法:通过一般处理程序ashx进行处理: 2)高级玩法:通过as ...

  5. 使用JQuery的Ajax调用SOAP-XML Web Services(Call SOAP-XML Web Services With jQuery Ajax)(译+摘录)

    假设有一个基于.Net的Web Service,其名称为SaveProduct POST /ProductService.asmx HTTP/1.1 Host: localhost Content-T ...

  6. jquery.ajax请求aspx和ashx的异同 Jquery Ajax调用aspx页面方法

    1.jquery.ajax请求aspx 请求aspx的静态方法要注意一下问题: (1)aspx的后台方法必须静态,而且添加webmethod特性 (2)在ajax方法中contentType必须是“a ...

  7. ASP.NET实现二维码 ASP.Net上传文件 SQL基础语法 C# 动态创建数据库三(MySQL) Net Core 实现谷歌翻译ApI 免费版 C#发布和调试WebService ajax调用WebService实现数据库操作 C# 实体类转json数据过滤掉字段为null的字段

    ASP.NET实现二维码 using System;using System.Collections.Generic;using System.Drawing;using System.Linq;us ...

  8. Ajax调用处理页面错误信息500的解决思路

    最近在做项目的时候遇到一个问题:(李昌辉) 在本地服务器上做好之后,部署到阿里云虚拟主机,结果访问页面出现问题,由于登录使用的是AJAX调用处理页面,所以在点击登录的时候没有任何反应. 打开F12调试 ...

  9. 使AJAX调用尽可能利用缓存特性

    优化网站设计(十四):使AJAX调用尽可能利用缓存特性 前言 网站设计的优化是一个很大的话题,有一些通用的原则,也有针对不同开发平台的一些建议.这方面的研究一直没有停止过,我在不同的场合也分享过这样的 ...

随机推荐

  1. .net的自定义JS控件,运用了 面向对象的思想 封装 了 控件(.net自定义控件开发的第一天)

    大家好!我叫刘晶,很高兴你能看到我分享的文章!希望能对你有帮助! 首先我们来看下几个例子 ,就能看到 如何 自定义控件! 业务需求: 制作  一个   属于 自己的    按钮 对象    ,然后 像 ...

  2. animation渐进实现点点点等待效果实例页面

    CSS代码: .ani_dot { font-family: simsun; } :root .ani_dot { display: inline-block; width: 1.5em; verti ...

  3. [译]JVM运行时数据区

    (本篇文章翻译自JVM Run-Time Data Areas) 这是我阅读JVM规范的笔记,而且我画了一个图来帮助我理解. 1.每一个单独的线程(非共享的)的数据区 针对每一个单独的线程的数据区包括 ...

  4. leetcode第40题--First Missing Positive

    题目: Given an unsorted integer array, find the first missing positive integer. For example,Given [1,2 ...

  5. android 删除SD卡或手机的缓存图像和文件夹

    public static final String TEMP_PHOTO_FILE_NAME = "temp_photo.jpg"; private static String ...

  6. Linux环境下搭建php开发环境的操作步骤

    本文主要记载了通过编译方式进行软件/开发环境的安装过程,其他安装方式忽略! 文章背景: 因为php和Apache等采用编译安装方式进行安装,然而编译安装方式,需要c,c++编译环境, 通过apt方式安 ...

  7. 【工作笔记四】去掉a标签超链接的虚线框的方法

    a{ blr:expression(this.onFocus=this.blur()); /* IE Opera */ outline:none; /* FF Opera */ } a:focus{ ...

  8. WCF RIA Services异常

    .svc处理程序映射缺失导致的WCF RIA Services异常 在确定代码.编译结果和数据库都正常的情况下,无法从数据库取到数据.错误提示:Sysyem.Net.WebException:远程服务 ...

  9. SpringMVC 国际化

    SpringMVC学习系列(8) 之 国际化 在系列(7)中我们讲了数据的格式化显示,Spring在做格式化展示的时候已经做了国际化处理,那么如何将我们网站的其它内容(如菜单.标题等)做国际化处理呢? ...

  10. ASP.NET WebApi 入门

    今天参照微软官方(http://www.asp.net)学习了WebApi,在这里摘录如下: 前言 HTTP 不只是为了生成 web 页面.它也是一个强大的平台,可以建设公开服务和数据的 Api.HT ...