结合AJAX的PHP开发之后退、前进和刷新
简介
第1部分介绍了如何用Sajax、PHP和JavaScript开发基本的相册。在为应用程序建立历史堆栈的过程中,我们将依靠客户端技术,并将其直接与第1部分的代码结合在一起。本文假设读者了解JavaScript和浏览器cookie。
在浏览器中保存状态
在网上冲浪的时候,总是从一个页面到另一个页面,从一个站点到另一个站点。在这个过程中,Web浏览器忠实地记录了您曾经到过何处的历史记录,创建了一条面包屑型(breadcrumbs)数字轨迹,沿着这条轨迹能够一步一步地回到出发点。后退按钮允许您回到上一个动作之前所在的位置,从这个意义上说它就是Web上的撤销按钮。
Web是一种按页划分的的媒体。浏览器工具栏中的后退和前进按钮指引着浏览器从一个页面移动到另一个页面。当Macromedia的Flash风行一时的时候,开发人员和用户发现富互联网应用程序(RichInternetApplication,RIA)打破了这种模式。用户可以在几个站点上浏览,然后登录一个基于Flash的网站,在这个网站上消磨几分钟。当用户单击后退按钮时,游戏结束了。用户没有回到先前的那个Flash站点,完全不知道到了什么地方。
对于完全基于Ajax的网站——RIA的另一种形式,情况也是如此。允许用户与一个页面进行多次交互的网站很容易受到后退按钮的困扰,或者受到任何历史记录按钮的困扰(就此而言)。前进和重载按钮的问题与后退按钮的问题一样。Web浏览器内置的内部历史记录机制是一个不可逃避的问题。出于安全的原因,开发人员不能篡改浏览器历史记录或者任何相关按钮。还有可用性的问题。设想一下,如果后退按钮突然弹出一个神秘的警告提示或者用户被打发到一个新的网站上去,用户该是多么困惑。
构建历史堆栈
虽然不能改变浏览器历史记录,但是可以自己构建一个在RIA中使用的历史记录。显然,它在某种程度上应该与浏览器的标准导航工具分开,但正如前面所说的,富应用程序在一定程度上背离了Web的页面到页面的标准模式。
我们将建立一个堆栈来管理应用程序的历史事件记录,也就是说存储一个列表,在表的最后添加元素。堆栈用于按照后进先出(LIFO)的顺序存储数据。虽然回退的时候并没有删除堆栈顶部的数据,但这个模型跟我们的需要非常接近。在JavaScript中,堆栈可以用数组来管理。
与堆栈在一起的还有一个指针,指示我们在堆栈中的当前位置。当我们在应用程序中单击的时候,新的事件将被压入堆栈顶部,指针指向最后添加的元素。单击应用程序的后退和前进按钮时,不会在堆栈中添加新的事件,而是移动堆栈的指针。想一想使用后退按钮时历史堆栈中会发生什么:浏览器返回上一次查看的页面,原来不能用的前进按钮突然之间变得可用了。浏览新的页面时,前进按钮再次变成灰色。浏览器历史记录中较晚保存的元素将被弹出堆栈,新的事件被压入堆栈顶部。我们将在自己创建的历史堆栈中再现这种行为。
我们的目标是创建一组可用的历史记录按钮:后退、前进和刷新
编写类
我们来看看历史堆栈中需要存储的数据或属性。前面已经讨论了堆栈(数组)和指针。stack_limit属性可以防止因为数据过多而造成的cookie溢出(参见清单1)。在实践中,我们希望在删除最老的记录之前能够存储40-50个事件。出于测试的目的,我们将该值设置为15。
清单1.历史堆栈的构造,包括类的属性
functionHistoryStack()
{
this.stack=newArray();
this.current=-1;
this.stack_limit=15;
}
除了这三个属性外,该类还需要一些方法来添加元素、检索堆栈数据以及将堆栈数据保存到浏览器cookie中。首先看一看addResource()方法,它用于将记录压入历史堆栈的堆栈顶部(参见清单2)。注意,如果堆栈的长度超过了stack_limit,那么最老的记录将从堆栈中移走。
清单2.addResource()方法,向历史堆栈的堆栈顶部添加记录
HistoryStack.prototype.addResource=function(resource)
{
if(this.stack.length>0){
this.stack=this.stack.slice(0,this.current+1);
}
this.stack.push(resource);
while(this.stack.length>this.stack_limit){
this.stack.shift();
}
this.current=this.stack.length-1;
this.save();
};
给历史堆栈添加的以下三个方法用于从该类中获取信息(参见清单3)。getCurrent()返回堆栈指针指向的当前记录,这在堆栈中导航的时候非常有用。hasPrev()和hasNext()方法返回Boolean值,告诉我们当前记录之前或之后是否还有记录,或者指示我们到达了堆栈顶部或堆栈尾部。这些方法很简单,但是确定后退和前进按钮的状态时很有用。
清单3.历史堆栈定义的方法
HistoryStack.prototype.addResource=function(resource)
HistoryStack.prototype.getCurrent=function()
{
returnthis.stack[this.current];
};
HistoryStack.prototype.hasPrev=function()
{
return(this.current>0);
};
HistoryStack.prototype.hasNext=function()
{
return(this.current<this.stack.length-1&&this.current>-1);
};
现在就可以向历史堆栈中添加记录并确定所在的位置了。但还是无法在堆栈中导航。清单4中定义的go()方法允许我们在堆栈中来回移动。通过传递正或负的增量就可以在堆栈中向前或向后移动。这与JavaScript内置的location.go()方法类似。既然模仿内置功能,为何不根据这些已有的方法建立模型呢?
此外,我们还可用该方法实现刷新功能。可以通过传递正或负的参数在堆栈中导航。传递零时则会刷新当前页面。