如何让触发ajax的button不消失,并且再按一次可以把显示的内容在隐藏起来,类似微博江湖的评论

保持登录。
单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.
在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。
所有提交的信息确保安全。
当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。
单击提交则表示您同意developerWorks
的条款和条件。 .
所有提交的信息确保安全。
developerWorks 社区:
我的概要信息
选择语言:
异步 JavaScript 和 XML(Asynchronous JavaScript and XML,Ajax)驱动的 Web 站点的主要挑战之一是缺少后退按钮。“” 系列包括两部分, 创建了 Ajax 相册应用程序,这一部分我们将使用 JavaScript 为其建立一个历史堆栈(history stack)。这个堆栈以 Web 浏览器中的历史记录工具为蓝本,为该应用程序提供后退、前进和刷新按钮。
(), 技术主管, ID Society
Mike Brittain 是
的技术主管,ID Society 是纽约市的一家交互营销代理公司。他拥有 10 年以上使用开放源码技术和语言开发网站和应用程序的经验。他曾在丹佛大学讲授脚本语言,从那里获得了硕士学位。您可以通过
与他联系。
简介 介绍了如何用 Sajax、PHP 和 JavaScript 开发基本的相册。在为应用程序建立历史堆栈的过程中,我们将依靠客户端技术,并将其直接与第 1 部分的代码结合在一起。本文假设读者了解 JavaScript 和浏览器 cookie。在浏览器中保存状态在网上冲浪的时候,总是从一个页面到另一个页面,从一个站点到另一个站点。在这个过程中,Web 浏览器忠实地记录了您曾经到过何处的历史记录,创建了一条面包屑型(breadcrumbs)数字轨迹,沿着这条轨迹能够一步一步地回到出发点。后退按钮允许您回到上一个动作之前所在的位置,从这个意义上说它就是 Web 上的撤销按钮。Web 是一种按页划分的的媒体。浏览器工具栏中的后退和前进按钮指引着浏览器从一个页面移动到另一个页面。当 Macromedia 的 Flash 风行一时的时候,开发人员和用户发现富互联网应用程序(Rich Internet Application,RIA)打破了这种模式。用户可以在几个站点上浏览,然后登录一个基于 Flash 的网站,在这个网站上消磨几分钟。当用户单击后退按钮时,游戏结束了。用户没有回到先前的那个 Flash 站点,完全不知道到了什么地方。对于完全基于 Ajax 的网站 —— RIA 的另一种形式,情况也是如此。允许用户与一个页面进行多次交互的网站很容易受到后退按钮的困扰,或者受到任何历史记录按钮的困扰(就此而言)。前进和重载按钮的问题与后退按钮的问题一样。Web 浏览器内置的内部历史记录机制是一个不可逃避的问题。出于安全的原因,开发人员不能篡改浏览器历史记录或者任何相关按钮。还有可用性的问题。设想一下,如果后退按钮突然弹出一个神秘的警告提示或者用户被打发到一个新的网站上去,用户该是多么困惑。构建历史堆栈虽然不能改变浏览器历史记录,但是可以自己构建一个在 RIA 中使用的历史记录。显然,它在某种程度上应该与浏览器的标准导航工具分开,但正如前面所说的,富应用程序在一定程度上背离了 Web 的页面到页面的标准模式。我们将建立一个堆栈来管理应用程序的历史事件记录,也就是说存储一个列表,在表的最后添加元素。堆栈用于按照后进先出(LIFO)的顺序存储数据。虽然回退的时候并没有删除堆栈顶部的数据,但这个模型跟我们的需要非常接近。在 JavaScript 中,堆栈可以用数组来管理。与堆栈在一起的还有一个指针,指示我们在堆栈中的当前位置。当我们在应用程序中单击的时候,新的事件将被压入堆栈顶部,指针指向最后添加的元素。单击应用程序的后退和前进按钮时,不会在堆栈中添加新的事件,而是移动堆栈的指针。想一想使用后退按钮时历史堆栈中会发生什么:浏览器返回上一次查看的页面,原来不能用的前进按钮突然之间变得可用了。浏览新的页面时,前进按钮再次变成灰色。浏览器历史记录中较晚保存的元素将被弹出堆栈,新的事件被压入堆栈顶部。我们将在自己创建的历史堆栈中再现这种行为。我们的目标是创建一组可用的历史记录按钮:后退、前进和刷新,如图 1 所示。图 1. 后退、前进和刷新的历史记录按钮显示在左侧,不可用状态显示在右侧可重用的设计JavaScript 使用非常宽松的方法创建对象和类,但仍然能够建立可重用的代码。首先列出历史堆栈需要的功能,然后用 JavaScript 建立堆栈模型。在把历史堆栈集成到相册应用程序之前,首先要建立一个简单的页面来测试其功能。这样做有两方面的好处:测试页有助于将精力集中到开发和测试类的核心功能上,建立单独的测试页可以避免混淆历史堆栈和相册的功能,从而确保可重用性。用 cookie 缓冲我们需要应用程序的历史记录在整个浏览器会话中都存在。只要用户仍在查看相册页面,历史堆栈对象就会一直存在。每当发生更改的时候,这个类就会将整个历史记录复制到浏览器 cookie 中。如果用户在同一个浏览器会话中离开该页之后又返回,那么将返回他离开该应用程序时所在的同一个位置。编写类我们来看看历史堆栈中需要存储的数据或属性。前面已经讨论了堆栈(数组)和指针。stack_limit 属性可以防止因为数据过多而造成的 cookie 溢出(参见清单 1)。在实践中,我们希望在删除最老的记录之前能够存储 40-50 个事件。出于测试的目的,我们将该值设置为 15。清单 1. 历史堆栈的构造,包括类的属性function HistoryStack ()
this.stack = new Array();
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 ()
return this.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() 方法类似。既然模仿内置功能,为何不根据这些已有的方法建立模型呢? 此外,我们还可用该方法实现刷新功能。可以通过传递正或负的参数在堆栈中导航。传递零时则会刷新当前页面。清单 4. 历史堆栈的 go() 方法HistoryStack.prototype.go = function(increment)
// Go back...
if (increment & 0) {
this.current = Math.max(0, this.current + increment);
// Go forward...
} else if (increment & 0) {
this.current = Math.min(this.stack.length - 1,
this.current + increment);
// Reload...
location.reload();
this.save();
};到目前为止,只要 HistoryStack 对象存在于当前文档中,这个新建的类就能正常工作。我们已经讨论了刷新页面会造成数据丢失的问题,现在来解决它。清单 5 中添加了在浏览器 cookie 中设置和访问数据的方法。所要做的只是设置每个 cookie 的名称值对。因为只需要在浏览器会话中保存 cookie,而不需要设置有效期。为了简化示例,我们不考虑其他参数,如 secure、domain 和 path。注意:如果该类需要对 cookie 做复杂处理,更明智的办法是使用完全独立的 cookie 管理类。建立和读取 cookie 有点偏离历史堆栈的正题。如果 JavaScript 允许指定方法和属性访问的作用域,也可以将这些方法设成私有的。清单 5. 建立和访问浏览器 cookie 的方法HistoryStack.prototype.setCookie = function(name, value)
var cookie_str = name + "=" + escape(value);
document.cookie = cookie_
HistoryStack.prototype.getCookie = function(name)
if (!name) return '';
var raw_cookies, tmp,
var cookies = new Array();
raw_cookies = document.cookie.split('; ');
for (i=0; i & raw_cookies. i++) {
tmp = raw_cookies[i].split('=');
cookies[tmp[0]] = unescape(tmp[1]);
if (cookies[name] != null) {
return cookies[name];
return '';
};定义了管理任何 cookie 的方法之后,可以编写另外两个类专门处理历史堆栈的类。save() 方法将堆栈转化成字符串并保存到 cookie 中,load() 重新将字符串解析成用于管理历史堆栈的数组(参见清单 6)。清单 6. save() 和 load() 方法HistoryStack.prototype.save = function()
this.setCookie('CHStack', this.stack.toString());
this.setCookie('CHCurrent', this.current);
HistoryStack.prototype.load = function()
var tmp_stack = this.getCookie('CHStack');
if (tmp_stack != '') {
this.stack = tmp_stack.split(',');
var tmp_current = parseInt(this.getCookie('CHCurrent'));
if (tmp_current &= -1) {
this.current = tmp_
};测试类可以用简单的 HTML 页面和一些 JavaScript 来测试完成的类。测试页面将在上方显示历史记录按钮,只有活动的按钮是突出显示并且可以单击的。我们没有建立复杂的测试应用程序,该页面在每次单击链接时仅仅生成随机数。这些数字就是记录到历史堆栈中的事件。堆栈也在页面上显示,指针标记的当前记录用粗体显示。清单 7. 测试历史堆栈的简单 HTML 页面&html&
&title&&/title&
&div id="historybuttons"&&/div&
&a href="#" onclick="do_add();"&Add Random
Resource&/a&
&div id="output" style="margin-top:40"&&/div&
&/html&在该 HTML 页面的头部需要添加清单 8 所示的 JavaScript 代码。这段代码首先实例化一个新的历史堆栈对象,并载入可能已经保存到浏览器 cookie 中的所有数据。我们定义了四个 do_*() 函数,这些事件处理程序将添加到后退、前进和刷新按钮的链接中,此外还有 Add Random Resource 链接,如清单 7 所示。display() 函数检查历史记录对象的当前状态,并为历史记录按钮生成 HTML。它还生成历史记录中存储的项目列表。清单 8. 集成历史记录类和测试页面的 JavaScript&script type="text/javascript" src="history.js"&&/script&
&script type="text/javascript"&
var myHistory = new HistoryStack();
myHistory.load();
function do_add()
var num = Math.round(Math.random() * 1000);
myHistory.addResource(num);
display();
function do_back()
myHistory.go(-1);
display();
function do_forward()
myHistory.go(1);
display();
function do_reload()
myHistory.go(0);
function display()
// Display history buttons
var str = '';
if (myHistory.hasPrev()) {
str += '&a href="#" onclick="do_back();"&'
+ '&img src="icons/back_on.gif" alt="Back"
str += '&img src="icons/back_off.gif" alt="" /& ';
if (myHistory.hasNext()) {
str += '&a href="#" onclick="do_forward(); return
+ '&img src="icons/forward_on.gif" alt="Forward" /&'
+ '&/a& ';
str += '&img src="icons/forward_off.gif" alt="" /& ';
str += '&a href="#" onclick="do_reload();"&'
+ '&img src="icons/reload.gif" alt="Reload"
document.getElementById("historybuttons").innerHTML =
// Display the current history stack, highlighting the current
// position.
var str = '&div&History:&/div&';
for (i=0; i & myHistory.stack. i++) {
if (i == myHistory.current) {
str += '&div&&b&' + myHistory.stack[i] +
'&/b&&/div&';
str += '&div&' + myHistory.stack[i] + '&/div&';
document.getElementById("output").innerHTML =
window.onload = function () {
display();
&/script&运行该测试页面,可以看到历史记录按钮反映了历史堆栈的状态(见图 2)。比如,第一次加载页面时,按钮都是灰色的。向堆栈中添加一些记录后,后退按钮就变成活动的了。如果在堆栈中回退,前进按钮就变亮了。还要注意的是,如果单击几次后退然后再单击 Add,那么堆栈会被截掉一部分,新的事件 被压入缩短的堆栈顶部。图 2. 历史堆栈的测试页面测试完该类后,就可以进入最激动人心的阶段了。集成历史记录对象和相册我们将从第 1 部分留下的问题开始,直接从相册页面调用历史堆栈。不需要修改任何 PHP 文件。首先需要添加一个 div 标记来存放历史记录按钮。如清单 7 所示。&div id="historybuttons"&&/div&历史堆栈代码被保存到一个 .js 文件中,该文件将链接到相册页面。&script type="text/javascript" src="history.js"&&/script&需要实例化历史堆栈对象并从缓冲区加载它们。这些操作可以添加到相册页面上已有脚本的前面。var myHistory = new HistoryStack();
myHistory.load();在针对历史堆栈的测试应用程序中,只存储随机数作为事件。我们可以在历史记录中存储需要的任何信息,但是要记住,当用户单击应用程序的后退按钮时,还要确定历史堆栈中的内容是什么。应用程序只有两个动作与 x_get_table() 和 x_get_image() 函数有关。因此对于每个表链接,可以存储名称 table 再加上 start 和 step 值作为事件标识符,比如 table-10-5。类似地,可以存储名称 image 和将被查看图像的 index,如 image-20。在第 1 部分中,相册中的每个链接都是由 get_table_link() 和 get_image_link() 两个函数生成的。通过编辑这些函数,可以在调用 Sajax 函数之前让该函数先调用历史堆栈。清单 9 以粗体显示了这些变化。清单 9. get_table_link() 和 get_image_link() 函数的更新版本function get_table_link ( $title, $start, $step ) {
$link = "myHistory.addResource('table-$start-$step'); "
."x_get_table($start, $step, to_window); "
return '&a href="#" onclick="' . $link . '"&' . $title
function get_image_link ( $title, $index ) {
$link = "myHistory.addResource('image-$index'); "
."x_get_image($index, to_window); "
return '&a href="#" onclick="' . $link . '"&' . $title .
}当应用程序进行 Sajax 调用时,to_window() 作为回调函数在页面上重新生成 HTML。在测试应用程序中,我们用函数 display()(清单 8)完成了两项任务:更新页面输出和更新历史记录按钮的状态。现在将在已有的 to_window() 函数体中添加下列函数调用:display_history_buttons();该函数的定义如清单 10 所示。清单 10. display_history_buttons() 函数function display_history_buttons()
var str = '';
if (myHistory.hasPrev()) {
str += '&a href="#" onclick="do_back();"&
&img src="icons/back_on.gif" alt="Back" /&&/a&';
str += '&img src="icons/back_off.gif" alt="" /&';
if (myHistory.hasNext()) {
str += '&a href="#" onclick="do_forward();"&
&img src="icons/forward_on.gif" alt="Forward" /&&/a&';
str += '&img src="icons/forward_off.gif" alt="" /&';
str += '&a href="#" onclick="do_reload();"&
&img src="icons/reload.gif" alt="Reload" /&&/a&';
document.getElementById("historybuttons").innerHTML =
}在开始跟踪相册应用程序的历史记录之前,只需要在页面加载过程中调用 x_get_table() 函数即可。这样就可以调用通过 Sajax 显示的初始表。 现在已经有了历史堆栈,但是我们不希望每次打开该应用程序时都要从头开始。相反,我们希望从离开的地方开始。因此需要添加 load_current() 函数以扩展应用程序,加载页面时会调用该函数。添加后退和前进按钮处理程序时,还将调用该函数,根据保存到历史堆栈中的事件 ID 来更新页面。 清单 11. load_current() 函数function load_current()
// No existing history.
if (myHistory.stack.length == 0) {
x_get_table(to_window);
myHistory.addResource('table-0-5');
// Load from history.
var current = myHistory.getCurrent();
var params = current.split('-');
if (params[0] == 'table') {
x_get_table(params[1], params[2], to_window);
} else if (params[0] == 'image') {
x_get_image(params[1], to_window);
}onload 处理程序需要进行相应的修改:window.onload = function () {
load_current();
};最后,添加清单 12 中的历史记录按钮处理例程。注意处理程序和测试应用程序的相似性。清单 12. 历史记录按钮事件处理程序function do_back()
myHistory.go(-1);
load_current();
function do_forward()
myHistory.go(1);
load_current();
function do_reload()
myHistory.go(0);
}至此就完成了历史堆栈到相册应用程序的集成。完成后的产品如图 3 所示。图 3. 与相册应用程序结合的历史记录按钮打开应用程序并单击链接,就会看到存储在浏览器 cookie 中的历史堆栈和指针。CHCurrent = 4
CHStack = table-0-5%2Cimage-1%2Cimage-2%2Cimage-3%2Ctable-3-5如果正在运行 Mozilla Firefox 并下载了 Web Developer Toolbar 扩展,那么这些操作就很容易实现。结束语我们介绍了如何创建一个自定义的历史堆栈来跟踪 Ajax 应用程序中的事件。可以在应用程序中添加 Web 浏览器上常见的后退、前进和刷新按钮来导航自定义的历史堆栈。为解决这一难题,我们确定了问题所在,创建了能应用于其他应用程序的可重用解决方案。我们没有直接在相册应用程序中建立历史堆栈,而是用一个简单的页面测试这个类。这样做有助于建立不会严格绑定到某个应用程序的解决方案,该解决方案可用于其他 Ajax 应用程序来解决同样的问题。
下载描述名字大小Part 2 source code6.5KB
参考资料 您可以参阅本文在 developerWorks 全球站点上的
。您可以参阅 。:在这里您可以找到更多关于 Ajax 的知识,包括 Ajax 基础入门、使用 Java, PHP 等语言开发 Ajax 应用的各种技巧和多种 Ajax 框架的技术信息。
关于 Sajax 工具包的基础知识,请阅读 “”。
请阅读 developerWorks 的 “” 系列文章,该系列包括五部分,详细介绍了 Ajax。
请阅读 developerWorks 的
“” 系列,了解使用 Ajax 技术创建网站之前需要知道的基本知识。
本文中使用了简单的 innerHTML() 方法来改写历史记录按钮。还可使用 “” 中讨论的技术来替换 HTML 标记。
结合 “” 应用您的 Ajax 知识,并创建其他的 Web 应用程序,比如图书订购应用程序。
Mozilla 的
提供关于编写对象和类的更多信息。
可用性对于站点的用户来说至关重要。请阅读 “” 和 “”,了解什么是最佳用户体验。
Mike Stenhouse 撰写了 “”。他的巧妙解决方案包括 iframes、URL 散列以及跨浏览器兼容的代码分支。
Brad Neuberg 编写的 “” 是将浏览器历史记录按钮与 Ajax 应用程序结合起来的另一种工具包。
请访问 IBM developerWorks 的 ,以进一步了解 PHP。
随时关注 。
请访问 developerWorks 的 ,那里提供了大量 how-to 信息、工具和项目更新,这些有助于您使用开放源码技术,并将这些技术与 IBM 产品结合使用。
Chris Pederick 的
能够查看和管理 cookie、CSS、图片、表单和其他内容,它是最有用的 Mozilla 扩展之一。
改进您的下一个开放源码开发项目,可通过下载或通过订阅免费的
获得这些软件。
加入 developerWorks 社区。
developerWorks: 登录
标有星(*)号的字段是必填字段。
保持登录。
单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件。
在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。
所有提交的信息确保安全。
选择您的昵称
当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。昵称长度在 3 至 31 个字符之间。
您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。
标有星(*)号的字段是必填字段。
(昵称长度在 3 至 31 个字符之间)
单击提交则表示您同意developerWorks 的条款和条件。 .
所有提交的信息确保安全。
IBM PureSystems(TM) 系列解决方案是一个专家集成系统
通过学习路线图系统掌握软件开发技能
软件下载、试用版及云计算
static.content.url=/developerworks/js/artrating/SITE_ID=10Zone=Open source, Web developmentArticleID=160314ArticleTitle=结合 Ajax 进行 PHP 开发,第 2 部分: 后退、前进和刷新publish-date=ajax回传数据显示后,触发一个函数?改怎么写?
[问题点数:100分,结帖人okayu]
ajax回传数据显示后,触发一个函数?改怎么写?
[问题点数:100分,结帖人okayu]
不显示删除回复
显示所有回复
显示星级回复
显示得分回复
只显示楼主
相关帖子推荐:
2010年5月 Web 开发大版内专家分月排行榜第二2009年8月 Web 开发大版内专家分月排行榜第二2009年7月 Web 开发大版内专家分月排行榜第二2007年10月 Web 开发大版内专家分月排行榜第二2007年9月 Web 开发大版内专家分月排行榜第二
2009年9月 Web 开发大版内专家分月排行榜第三
2010年5月 Web 开发大版内专家分月排行榜第二2009年8月 Web 开发大版内专家分月排行榜第二2009年7月 Web 开发大版内专家分月排行榜第二2007年10月 Web 开发大版内专家分月排行榜第二2007年9月 Web 开发大版内专家分月排行榜第二
2009年9月 Web 开发大版内专家分月排行榜第三
2014年2月 总版技术专家分月排行榜第二2013年4月 总版技术专家分月排行榜第二
2007年12月 总版技术专家分月排行榜第三
本帖子已过去太久远了,不再提供回复功能。AJAX:如何处理书签和后退按钮 - 设计前沿
AJAX:如何处理书签和后退按钮
文章出处:bea 作者:Brad Neuberg 发布时间:
????? 关键词:AJAX:如何处理书签和后退按钮本文将展示一个开源JavaScript库,该脚本库给AJAX应用程序带来了书签和后退按钮支持。在学习完这个教程后,开发人员将能够获得对一个AJAX问题的解决方案(甚至连Google Maps和Gmail现在都不提供该解决方案):一个强大的、可用的书签和后退前进功能,其操作行为如同其他的Web应用程序一样。
本文将阐述目前AJAX应用程序在使用书签和后退按钮方面所面临的严重问题;展示Really Simple History(RSH)库&&一个可以解决以上问题的开源框架,并提供几个运行中的例子。
本文所展示的这个框架的主要发明分为两部分。首先是一个隐藏的HTML表单,用于缓存大量短期会话的客户端信息;这种缓存功能为页面导航提供了强大的支持。其次是超链接锚点和隐藏Iframe的组合,它们被嵌入后退和前进按钮,用来截获和记录浏览器的历史记录事件。以上两种技术都被包装在一个简单的JavaScript库中来简化开发。
书签和后退按钮在传统的多页面Web应用程序中运行得非常好。当用户浏览web站点的时候,其浏览器的地址栏记录随新的URL而更新,这些记录可以被粘贴到电子邮件或者书签中供以后使用。后退和前进按钮也可以正常操作,使用户可以在访问过的页面中向前或向后翻动。
但是AJAX应用程序却不一样,它们是运行在单个Web页面中的复杂程序。浏览器并不是为这类程序而构建的&&这类Web应用程序已经过时,它们在每次鼠标点击的时候都需要重新刷新整个页面。
在这种类似于Gmail的AJAX软件中,浏览器的地址栏在用户选择功能和改变程序状态的时候保持不变,这使得无法在特定的应用程序视图中使用书签。此外,如果用户按下&后退&按钮来&撤销&上次的操作,他们会惊奇地发现,浏览器会完全离开该应用程序的Web页面。
开源RSH框架可以解决这些问题,它为AJAX应用程序提供了书签和控制后退、前进按钮的功能。RSH目前还处于Beta阶段,可以在Firefox 1.0、Netscape 7+、Internet Explorer 6+等浏览器上运行;目前还不支持Safari。
目前有几个AJAX框架对书签和历史记录问题有所帮助;但这些框架目前都有几个由于实现而造成的重大Bug。此外,很多AJAX历史记录框架被绑定到较大的库上,例如Backbase和Dojo;这些框架为AJAX应用程序引入了完全不同的编程模型,迫使开发人员使用全新的方式来获得历史记录功能。
相较之下,RSH是一个可以包含在现有AJAX系统中的简单模块。此外,RSH库采用了一些技术以避免产生影响其他历史记录框架的Bug。
RSH框架由两个JavaScript类组成:DhtmlHistory和HistoryStorage。
DhtmlHistory类为AJAX应用程序提供历史记录抽象。AJAX页面使用add()方法添加历史记录事件到浏览器,指定新的地址和相关的历史记录数据。DhtmlHistory类使用一个锚散列(如#new-location)更新浏览器当前的URL,同时把历史记录数据和该新URL关联。AJAX应用程序将自己注册为历史记录的监听器,当用户使用后退和前进按钮进行浏览时,历史记录事件被触发,为浏览器提供新的位置以及与add()调用一起保存的任何历史记录数据。
第二个类:HistoryStorage,允许开发人员保存任意数量的已存历史记录数据。在普通Web页面中,当用户导航到一个新的web站点时,浏览器卸载并清除web页面上的所有应用程序和JavaScript状态;如果用户用后退按钮返回,所有的数据都丢失了。HistoryStorage类通过一个包含简单散列表方法(例如put()、get()、hasKey())的API来解决这类问题。上面的方法允许开发人员在用户离开Web页面之后保存任意数量的数据;当用户按后退按钮重新返回时,历史记录数据可以通过HistoryStorage类来访问。在内部,我们通过使用隐藏的表单字段来实现此功能,这是因为浏览器会自动保存表单字段中的值,甚至在用户离开Web页面的时候也如此。
让我们先从一个简单的例子开始。
首先,任何需要使用RSH框架的页面都必须包含dhtmlHistory.js脚本:
以下为引用的内容:<!-- Load the Really Simple History framework --><script type=&text/javascript&src=&../../framework/dhtmlHistory.js&></script>
DHTML历史记录应用程序也必须在与AJAX Web页面相同的目录下包含blank.html文件;这个文件与RSH框架打包在一起,且对于Internet Explorer来说是必需的。顺便提一下,RSH使用一个隐藏Iframe来跟踪和添加Internet Explorer的历史记录变化;这个Iframe需要我们指定一个实际的文件位置才能正常工作,这就是blank.html。
RSH框架创建了一个叫做dhtmlHistory的全局对象,这是操纵浏览器历史记录的入口点。使用dhtmlHistory的第一步是在Web页面加载完成后初始化dhtmlHistory对象:
以下为引用的内容:
window.onload =
function initialize() { // initialize the DHTML History // framework dhtmlHistory.initialize();
然后,开发人员使用dhtmlHistory.addListener()方法订阅历史记录变化事件。这个方法带有一个JavaScript回调函数,当DHTML历史记录变化事件发生时,该函数接收两个参数:新的页面位置以及任何可与该事件关联的可选历史记录数据:
以下为引用的内容:
window.onload =
function initialize() { // initialize the DHTML History // framework dhtmlHistory.initialize();
 // subscribe to DHTML history change // events dhtmlHistory.addListener(historyChange);  historyChange()方法很简单,该函数在用户导航到一个新位置后接收newLocation以及任何与该事件关联的可选historyData。
/** Our callback to receive history changeevents. */function historyChange(newLocation, historyData) { debug(&A history change has occurred: &  + &newLocation=&+newLocation  + &, historyData=&+historyData,   true);}
上面用到的debug()方法是定义在示例源文件中的一个实用函数,它与完整示例打包在一起供下载。debug()只是用来将消息打印到Web页面上;第二个布尔型参数(在上述代码中值为true)控制是否在打印新的调试消息之前清除原有的全部消息。
开发人员使用add()方法添加历史记录事件。添加历史记录事件涉及为历史记录变化指定一个新地址,例如edit:SomePage,以及提供一个和该事件一起保存的可选historyData值。
以下为引用的内容:
window.onload =
function initialize() { // initialize the DHTML History // framework dhtmlHistory.initialize();
 // subscribe to DHTML history change // events dhtmlHistory.addListener(historyChange);
 // if this is the first time we have // loaded the page... if (dhtmlHistory.isFirstLoad()) {  debug(&Adding values to browser & + &history&, false);  // start adding history  dhtmlHistory.add(&helloworld&, &Hello World Data&);  dhtmlHistory.add(&foobar&, 33);  dhtmlHistory.add(&boobah&, true);
  var complexObject = new Object();  complexObject.value1 = &This is the first value&;  complexObject.value2 = &This is the second data&;  complexObject.value3 = new Array();  complexObject.value3[0] = &array 1&;  complexObject.value3[1] = &array 2&;
  dhtmlHistory.add(&complexObject&, complexObject);
在add()被调用之后,新的地址将立即作为一个锚值(链接地址)显示在浏览器的URL地址栏中。例如,对地址为的AJAX Web页面调用dhtmlHistory.add(&helloworld&, &Hello World Data&)之后,用户将会在其浏览器URL地址栏中看到如下的地址:
然后用户可以将这个页面做成书签,如果以后用到这个书签,AJAX应用程序可以读取#helloworld值,并用它来初始化Web页面。散列后面的地址值是RSH框架可以透明编码和解码的URL地址。
HistoryData非常有用,它保存比简单的URL更为复杂的AJAX地址变化状态。这是一个可选值,可以是任何JavaScript类型,例如Number、String或Object。使用该保存功能的一个例子是在一个富文本编辑器中保存所有文本(比如在用户离开当前页面时)。当用户再回到这个地址时,浏览器将会将该对象返回给历史记录变化监听器。
开发人员可以为historyData提供带有嵌套对象和表示复杂状态的数组的完整JavaScript对象;JSON (JavaScript Object Notation)所支持的在历史记录数据中都支持,包括简单数据类型和null类型。然而,DOM对象以及可用脚本编写的浏览器对象(如XMLHttpRequest)不会被保存。请注意,historyData并不随书签一起保存,当浏览器关闭,浏览器缓存被清空,或者用户清除历史记录的时候,它就会消失。
使用dhtmlHistory的最后一步是isFirstLoad()方法。在某些浏览器中,如果导航到一个Web页面,再跳转到另一个不同的页面,然后按&后退&按钮返回到起始的站点,第一页将完全重新加载,并触发onload事件。这样会对想要在第一次加载页面时用某种方式对其进行初始化(而其后则不使用这种方式重新加载该页面)的代码造成破坏。isFirstLoad()方法可以区分是第一次加载一个Web页面还是用户导航到保存在历史记录中的Web页面时触发的&假加载&事件。
在示例代码中,我们只想在第一次加载页面的时候添加历史记录事件;如果用户在加载页面后按后退按钮返回该页面,我们就不想重新添加任何历史记录事件:
以下为引用的内容:
window.onload =
function initialize() { // initialize the DHTML History // framework dhtmlHistory.initialize();
 // subscribe to DHTML history change // events dhtmlHistory.addListener(historyChange);
 // if this is the first time we have // loaded the page... if (dhtmlHistory.isFirstLoad()) {  debug(&Adding values to browser &+ &history&, false);  // start adding history  dhtmlHistory.add(&helloworld&, &Hello World Data&);  dhtmlHistory.add(&foobar&, 33);  dhtmlHistory.add(&boobah&, true);
  var complexObject = new Object();  complexObject.value1 = &This is the first value&;  complexObject.value2 = &This is the second data&;  complexObject.value3 = new Array();  complexObject.value3[0] = &array 1&;  complexObject.value3[1] = &array 2&;
  dhtmlHistory.add(&complexObject&, complexObject);
让我们继续使用historyStorage类。类似于dhtmlHistory,historyStorage通过一个叫historyStorage的全局对象来公开它的功能。该对象有几个模拟散列的方法,比如put(keyName、keyValue)、get(keyName)和hasKey(keyName)。键名称必须是字符串,同时键值可以是复杂的JavaScript对象甚至是XML格式的字符串。在我们的源代码例子中,在第一次加载页面时,我们使用put()将简单的XML放入historyStorage:
以下为引用的内容:
window.onload =
function initialize() { // initialize the DHTML History // framework dhtmlHistory.initialize();
 // subscribe to DHTML history change // events dhtmlHistory.addListener(historyChange);
 // if this is the first time we have // loaded the page... if (dhtmlHistory.isFirstLoad()) {  debug(&Adding values to browser & + &history&, false);  // start adding history  dhtmlHistory.add(&helloworld&, &Hello World Data&);  dhtmlHistory.add(&foobar&, 33);  dhtmlHistory.add(&boobah&, true);
  var complexObject = new Object();  complexObject.value1 = &This is the first value&;  complexObject.value2 = &This is the second data&;  complexObject.value3 = new Array();  complexObject.value3[0] = &array 1&;  complexObject.value3[1] = &array 2&;
  dhtmlHistory.add(&complexObject&, complexObject);
  // cache some values in the history  // storage  debug(&Storing key 'fakeXML' into & + &history storage&, false);  var fakeXML =    '<?xml version=&1.0& '   + 'encoding=&ISO-8859-1&?>'   + '<foobar>'   + '<foo-entry/>'   + '</foobar>';  historyStorage.put(&fakeXML&, fakeXML);}
然后,如果用户离开页面后又通过后退按钮返回该页面,我们可以使用get()方法提取保存的值,或者使用hasKey()方法检查该值是否存在。
以下为引用的内容:
window.onload =
function initialize() { // initialize the DHTML History // framework dhtmlHistory.initialize();
 // subscribe to DHTML history change // events dhtmlHistory.addListener(historyChange);
 // if this is the first time we have // loaded the page... if (dhtmlHistory.isFirstLoad()) {  debug(&Adding values to browser & + &history&, false);  // start adding history  dhtmlHistory.add(&helloworld&, &Hello World Data&);  dhtmlHistory.add(&foobar&, 33);  dhtmlHistory.add(&boobah&, true);
  var complexObject = new Object();  complexObject.value1 = &This is the first value&;  complexObject.value2 = &This is the second data&;  complexObject.value3 = new Array();  complexObject.value3[0] = &array 1&;  complexObject.value3[1] = &array 2&;
  dhtmlHistory.add(&complexObject&, complexObject);
  // cache some values in the history  // storage  debug(&Storing key 'fakeXML' into & + &history storage&, false);  var fakeXML = '<?xml version=&1.0& ' + 'encoding=&ISO-8859-1&?>'   + '<foobar>' + '<foo-entry/>' + '</foobar>';  historyStorage.put(&fakeXML&, fakeXML); }
 // retrieve our values from the history // storage var savedXML = historyStorage.get(&fakeXML&); savedXML = prettyPrintXml(savedXML); var hasKey = historyStorage.hasKey(&fakeXML&); var message = &historyStorage.hasKey('fakeXML')=&   + hasKey + &<br>&   + &historyStorage.get('fakeXML')=<br>&   + savedXML; debug(message, false);}
prettyPrintXml()是一个定义在完整示例源代码中的实用方法;此函数准备在web页面中显示以便用于调试的简单XML。
请注意,相关数据只在该页面的历史记录中进行持久化;如果浏览器被关闭,或者用户打开一个新窗口并再次键入AJAX应用程序的地址,则该历史记录数据对于新的Web页面不可用。历史记录数据只有在用到后退或前进按钮时才被持久化,当用户关闭浏览器或清空缓存的时候就会消失。如果想真正长期持久化,请参阅Ajax MAssive Storage System (AMASS)。
我们的简单示例已经完成。
示例2:O'Reilly Mail
我们的第二个例子是一个简单的AJAX电子邮件模拟应用程序的示例,即O'Reilly Mail,它类似于Gmail。O'Reilly Mail描述了如何使用dhtmlHistory类来控制浏览器的历史记录,以及如何使用historyStorage对象来缓存历史记录数据。
O'Reilly Mail用户界面由两部分组成。在页面的左边是一个带有不同电子邮件文件夹和选项的菜单,例如收件箱、草稿箱等。当用户选择了一个菜单项(如收件箱),就用这个菜单项的内容更新右边的页面。在一个现实应用程序中,我们会远程获取并显示选择的信箱内容,不过在O'Reilly Mail中,我们只显示已选择的选项。
O'Reilly Mail使用RSH框架向浏览器历史记录中添加菜单变化并更新地址栏,允许用户利用浏览器的后退和前进按钮为应用程序做收藏书签和跳到上次变化的菜单。
我们添加一个特殊的菜单项&&地址簿,以说明如何来使用historyStorage。地址簿是一个由联系人名称和邮件地址组成的JavaScript数组,在一个现实应用程序中,我们会从一台远程服务器取得这个数组。不过,在O'Reilly Mail中,我们在本地创建这个数组,添加几个名称和电子邮件地址,然后将其保存在historyStorage对象中。如果用户离开Web页面后又返回该页面,那么O'Reilly Mail应用程序将重新从缓存检索地址簿,而不是再次联系远程服务器。
我们用initialize()方法保存和检索地址簿:
以下为引用的内容:
/** Our function that initializes when the pageis finished loading. */function initialize() {// initialize the DHTML History frameworkdhtmlHistory.initialize();
// add ourselves as a DHTML History listenerdhtmlHistory.addListener(handleHistoryChange);
// if we haven't retrieved the address book// yet, grab it and then cache it into our// history storageif (window.addressBook == undefined) { // Store the address book as a global // object. // In a real application we would remotely // fetch this from a server in the // background. window.addressBook =  [&Brad Neuberg &,  &John Doe &,  &Deanna Neuberg &];
 // cache the address book so it exists // even if the user leaves the page and // then returns with the back button historyStorage.put(&addressBook&, addressBook);}else { // fetch the cached address book from // the history storage window.addressBook = historyStorage.get(&addressBook&);}
处理历史记录变化的代码也很简单。在下面的源代码中,无论用户按后退还是前进按钮,都将调用handleHistoryChange。使用O'Reilly Mail定义的displayLocation实用方法,我们可得到newLocation并使用它将我们的用户界面更新到正确的状态。
以下为引用的内容:
/** Handles history change events. */function handleHistoryChange(newLocation, historyData) { // if there is no location then display // the default, which is the inbox if (newLocation == &&) {  newLocation = &section:inbox&; }
 // extract the section to display from // newLocation will // begin with the word &section:&  newLocation = newLocation.replace(/section\:/, &&);
 // update the browser to respond to this // DHTML history change displayLocation(newLocation, historyData);}
/** Displays the given location in the right-hand side content area. */function displayLocation(newLocation,sectionData) { // get the menu element that was selected var selectedElement = document.getElementById(newLocation);
 // clear out the old selected menu item var menu = document.getElementById(&menu&); for (var i = 0; i < menu.childNodes. i++) {  var currentElement = menu.childNodes[i];  // see if this is a DOM Element node  if (currentElement.nodeType == 1) {   // clear any class name   currentElement.className = &&;  }  }
 // cause the new selected menu item to // appear differently in the UI selectedElement.className = &selected&;
 // display the new section in the right-hand // determine what  // our sectionData is
 // display the address book differently by // using our local address data we cached // earlier if (newLocation == &addressbook&) {  // format and display the address book  sectionData = &<p>Your addressbook:</p>&;  sectionData += &<ul>&;
  // fetch the address book from the cache  // if we don't have it yet  if (window.addressBook == undefined) {   window.addressBook = historyStorage.get(&addressBook&);  }
  // format the address book for display  for (var i = 0; i < window.addressBook. i++) {   sectionData += &<li>&    + window.addressBook[i]    + &</li>&;   }
  sectionData += &</ul>&; }
 // If there is no sectionData, then  //
in this example // we use fake data for everything but the // address book if (sectionData == null) {  // in a real application we would remotely  // fetch this section's content  sectionData = &<p>This is section: & + selectedElement.innerHTML + &</p>&;  }
 // update the content's title and main text var contentTitle = document.getElementById(&content-title&); var contentValue = document.getElementById(&content-value&); contentTitle.innerHTML = selectedElement.innerHTML; contentValue.innerHTML = sectionD}
现在我们已经了解了如何使用RSH API来使AJAX应用程序支持书签以及后退和前进按钮,并提供了示例代码,您可参考该示例来创建自己的应用程序。希望您能利用书签和历史记录的支持来增强AJAX应用程序。
??????????????}

我要回帖

更多关于 长微博 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信