论坛首页 Web前端技术论坛

Dojo和Ajax 程序的浏览器History 控制

浏览 17762 次
该帖已经被评为良好帖
作者 正文
   发表时间:2007-12-07  

web应用程序都面临浏览器上的history功能的困扰,前进,后退,刷新,将是你的程序失控,重复提交,丢失数据等等场景让你焦头烂额,运行的好好的程序,被客户随便摆弄一下就错误百出。这些就是客户心智和程序员心智不同产生的冲突。

最初的web程序只是一些静态的网页,一般都通过地址栏的URL地址来进行定位,所以,浏览器集成了很方便的History功能,让你在浏览的历史记录中来回切换。可是,随着复杂应用程序开始越来越多的通过浏览器来作为客户端,噩梦就开始了。

近年来,Ajax技术的兴起为程序设计者和客户提供了不同的技术实现和用户体验,Ajax火了起来,也开始颠覆了传统的web操作和应用传统。但是浏览器并没有相应的来迎合这些变化,这样的话, Ajax 程序也同样的面临浏览器的干扰,而History功能就是其中让人头疼的一个。

越来越多的程序员面临这个问题,开始考虑解决之道,解决的方案五花八门,不过都这能解决问题的一部分,无法从根本上解决这个问题。要根本解决这个问题,只怕需要浏览器的厂商和标准部门针对Ajax一起来想出一个标准化的处理方式。

当然我们没有时间来等待别人来帮助我们解决问题,我这里介绍一下Dojo 解决这个问题的方法,同时研究一下它的实现原理。

需要解决的问题

Ajax程序进行页面内容变化的时候,并没有刷新整个页面也没有改变浏览器地址,所以如果进行以下的操作将会出现无法意料的问题:

行为案例:1search 页面--2search-->3显示列表在本页面--4点击列表中的某条记录--5页面切换-->6所选记录的详细内容页面-->7编辑并保存-->8停留在原页面,提示保存成功-->9返回--.10页面切换-->11search页面

上面的步骤都不会导致浏览器地址变化,因为我们的应用是单页面的frame。

这个案例涉及到两个页面(黑体 1,6),4 个动作(红色 2,4,7,9)

后退/ 前进: 如果在step6的时候,如果浏览器的后退按钮可以点击的话(一般如果你之前没有访问过别的url,那么将不会有后退地址),将不会回到3或者1,而是1之前你访问过的地址。

刷新:如果在step6的时候,你点击刷新,将不会刷新step6所在的页面,因为浏览器的地址没有发生变化,你会发现,页面刷新之后来到了step1.

收藏: 同上,你收藏的step1所在的页面。

客户看到他花钱买的程序却是这样的行为,客户岂不是要疯掉!!!

解决之道

1. dojo

 dojo1.0 提供dojo.back 对象来处理这里问题,可以记录页面状态到一个堆栈对象(historyStack)中。但是这个historyStack开始是空的,当我们进入的首页的时候,可以通过setInitialState 方法设置他的第一个状态,如

js 代码
  1. dojo.back.setInitialState(currentState);  

之后每一次页面状态变化,你都可以将这个状态用书签记录下来,如

js 代码
  1. dojo.back.addToHistor(currentState);  

state 代表你需要记录的页面状态,一般包括下面几个属性:

back 函数  //当用户点击后退按钮,并且跳转到这个状态的时候将被调用。
forward 函数  //  当用户点击前进按钮,并且跳转到这个状态的时候将被调用。
changeUrl 布尔类型或者字符串 布尔类型指示是否为当前状态创建一个唯一的hash值 如果是一个字符串,那么将使用这个字符串而不是hash值。

  1. var state = {   
  2.     back: function() { alert("Back was clicked!"); 
  3.         dojo.back.addToHistory(repeatState); },   
  4.     forward: function() { alert("Forward was clicked!"); }   
  5.  };  

dojo 的back对象将会在用户点击浏览器后退按钮的时候自动将当前state从historyStack中Pop出来。同时进入到前一个state。

下面摘选自dojo库的back.js

js 代码
  1. function handleBackButton(){   
  2.         //summary: private method. Do not call this directly.   
  3.   
  4.         //The "current" page is always at the top of the history stack.   
  5.         //console.debug("handlingBackButton");   
  6.         var current = historyStack.pop();   
  7.         if(!current){ return; }   
  8.         var last = historyStack[historyStack.length-1];   
  9.         if(!last && historyStack.length == 0){   
  10.             last = initialState;   
  11.         }   
  12.         if(last){   
  13.             if(last.kwArgs["back"]){   
  14.                 last.kwArgs["back"]();   
  15.             }else if(last.kwArgs["backButton"]){   
  16.                 last.kwArgs["backButton"]();   
  17.             }else if(last.kwArgs["handle"]){   
  18.                 last.kwArgs.handle("back");   
  19.             }   
  20.         }   
  21.         forwardStack.push(current);   
  22.         //console.debug("done handling back");   
  23.     }  

完整的例子,请看dojo1.0的发行包里面的back.html(dojo/tests/back.html),里面有完成的例子。

 

dojo怎么控制到后退按钮的呢?怎么记录书签,其中的奥妙何在呢?那就要看iframe在这里起到什么作用了。

 

2.  利用iframe 了控制每个页面的书签(bookmark)

 在页面地址没有变化的情况下,怎么记录书签呢?怎么样让用户能够收藏呢?如果要能够收藏,地址一定要变化,但是地址变化的时候又要确保页面的内容不发生变化。How to do?

Yes, Use # , 增加书签到地址后面,如: http://yourdomain/yourpage#bookmark 这样的话,地址栏变化了,那么后退按钮也就有了历史记录了。别高兴的太早,Ie并不是这样。Ie并不会将http://yourdomain/yourpage#bookmarkhttp://yourdomain/yourpage认为是两个页面,所以也就不会加入到History中,怎么处理这个问题呢?iframe在这里派上作用拉。通过设置iframe的src属性可以让Ie将这些状态记录到history中。

 

参考:http://www.contentwithstyle.co.uk/Articles/38/fixing-the-back-button-and-enabling-bookmarking-for-ajax-apps

 http://codinginparadise.org/weblog/2005/09/ajax-history-libraries.html

js 代码
   发表时间:2007-12-11  
写得不错,正好也在看DOJO
0 请登录后投票
   发表时间:2007-12-12  
不错。正被这个问题困扰呢。
0 请登录后投票
   发表时间:2007-12-26  
如果不用dojo,也不用Ajax,怎么控制浏览器的前进和后退
0 请登录后投票
   发表时间:2007-12-27  
前进后退我们是无法控制的。只能针对性的使用一些诡计解决我们面对的问题。
0 请登录后投票
   发表时间:2007-12-27  
最好就是尽量少用Ajax 因为还不成熟,框架的Bug也太多
0 请登录后投票
   发表时间:2008-01-08  
jelly 写道

web应用程序都面临浏览器上的history功能的困扰,前进,后退,刷新,将是你的程序失控,重复提交,丢失数据等等场景让你焦头烂额,运行的好好的程序,被客户随便摆弄一下就错误百出。这些就是客户心智和程序员心智不同产生的冲突。

最初的web程序只是一些静态的网页,一般都通过地址栏的URL地址来进行定位,所以,浏览器集成了很方便的History功能,让你在浏览的历史记录中来回切换。可是,随着复杂应用程序开始越来越多的通过浏览器来作为客户端,噩梦就开始了。

近年来,Ajax技术的兴起为程序设计者和客户提供了不同的技术实现和用户体验,Ajax火了起来,也开始颠覆了传统的web操作和应用传统。但是浏览器并没有相应的来迎合这些变化,这样的话, Ajax 程序也同样的面临浏览器的干扰,而History功能就是其中让人头疼的一个。

越来越多的程序员面临这个问题,开始考虑解决之道,解决的方案五花八门,不过都这能解决问题的一部分,无法从根本上解决这个问题。要根本解决这个问题,只怕需要浏览器的厂商和标准部门针对Ajax一起来想出一个标准化的处理方式。

当然我们没有时间来等待别人来帮助我们解决问题,我这里介绍一下Dojo 解决这个问题的方法,同时研究一下它的实现原理。

需要解决的问题

Ajax程序进行页面内容变化的时候,并没有刷新整个页面也没有改变浏览器地址,所以如果进行以下的操作将会出现无法意料的问题:

行为案例:1search 页面--2search-->3显示列表在本页面--4点击列表中的某条记录--5页面切换-->6所选记录的详细内容页面-->7编辑并保存-->8停留在原页面,提示保存成功-->9返回--.10页面切换-->11search页面

上面的步骤都不会导致浏览器地址变化,因为我们的应用是单页面的frame。

这个案例涉及到两个页面(黑体 1,6),4 个动作(红色 2,4,7,9

后退/ 前进: 如果在step6的时候,如果浏览器的后退按钮可以点击的话(一般如果你之前没有访问过别的url,那么将不会有后退地址),将不会回到3或者1,而是1之前你访问过的地址。

刷新:如果在step6的时候,你点击刷新,将不会刷新step6所在的页面,因为浏览器的地址没有发生变化,你会发现,页面刷新之后来到了step1.

收藏: 同上,你收藏的step1所在的页面。

客户看到他花钱买的程序却是这样的行为,客户岂不是要疯掉!!!

解决之道

1. dojo

 dojo1.0 提供dojo.back 对象来处理这里问题,可以记录页面状态到一个堆栈对象(historyStack)中。但是这个historyStack开始是空的,当我们进入的首页的时候,可以通过setInitialState 方法设置他的第一个状态,如

js 代码
  1. dojo.back.setInitialState(currentState);  

之后每一次页面状态变化,你都可以将这个状态用书签记录下来,如

js 代码
  1. dojo.back.addToHistor(currentState);  

state 代表你需要记录的页面状态,一般包括下面几个属性:

back 函数  //当用户点击后退按钮,并且跳转到这个状态的时候将被调用。
forward 函数  //  当用户点击前进按钮,并且跳转到这个状态的时候将被调用。
changeUrl 布尔类型或者字符串 布尔类型指示是否为当前状态创建一个唯一的hash值 如果是一个字符串,那么将使用这个字符串而不是hash值。

  1. var state = {   
  2.     back: function() { alert("Back was clicked!"); 
  3.         dojo.back.addToHistory(repeatState); },   
  4.     forward: function() { alert("Forward was clicked!"); }   
  5.  };  

dojo 的back对象将会在用户点击浏览器后退按钮的时候自动将当前state从historyStack中Pop出来。同时进入到前一个state。

下面摘选自dojo库的back.js

js 代码
  1. function handleBackButton(){   
  2.         //summary: private method. Do not call this directly.   
  3.   
  4.         //The "current" page is always at the top of the history stack.   
  5.         //console.debug("handlingBackButton");   
  6.         var current = historyStack.pop();   
  7.         if(!current){ return; }   
  8.         var last = historyStack[historyStack.length-1];   
  9.         if(!last && historyStack.length == 0){   
  10.             last = initialState;   
  11.         }   
  12.         if(last){   
  13.             if(last.kwArgs["back"]){   
  14.                 last.kwArgs["back"]();   
  15.             }else if(last.kwArgs["backButton"]){   
  16.                 last.kwArgs["backButton"]();   
  17.             }else if(last.kwArgs["handle"]){   
  18.                 last.kwArgs.handle("back");   
  19.             }   
  20.         }   
  21.         forwardStack.push(current);   
  22.         //console.debug("done handling back");   
  23.     }  

完整的例子,请看dojo1.0的发行包里面的back.html(dojo/tests/back.html),里面有完成的例子。

 

dojo怎么控制到后退按钮的呢?怎么记录书签,其中的奥妙何在呢?那就要看iframe在这里起到什么作用了。

 

2.  利用iframe 了控制每个页面的书签(bookmark

 在页面地址没有变化的情况下,怎么记录书签呢?怎么样让用户能够收藏呢?如果要能够收藏,地址一定要变化,但是地址变化的时候又要确保页面的内容不发生变化。How to do?

Yes, Use # , 增加书签到地址后面,如: http://yourdomain/yourpage#bookmark 这样的话,地址栏变化了,那么后退按钮也就有了历史记录了。别高兴的太早,Ie并不是这样。Ie并不会将http://yourdomain/yourpage#bookmarkhttp://yourdomain/yourpage认为是两个页面,所以也就不会加入到History中,怎么处理这个问题呢?iframe在这里派上作用拉。通过设置iframe的src属性可以让Ie将这些状态记录到history中。

 

参考:http://www.contentwithstyle.co.uk/Articles/38/fixing-the-back-button-and-enabling-bookmarking-for-ajax-apps

 http://codinginparadise.org/weblog/2005/09/ajax-history-libraries.html

js 代码
0 请登录后投票
   发表时间:2008-01-13  
Dojo这个框架的一大亮点就是它的IO设计,可以享受集中控制的好处。
它的io进行了统一封装,使用bind接口通讯,并进行了排队。这样的封装也就支持了它通过iframe来模拟前进后退,非常方便。
这一点它比Prototype和JQuery这样的轻封装占有了一些优势,也方便你扩展一些Js上的AOP机制上去。


但是它还有不适用场合:使用iframe通讯的场合(如跨子域),或者scriptio的时候,不能用history。
0 请登录后投票
   发表时间:2008-01-16  
是挺不错,哪里可以提供dojo api和教程
0 请登录后投票
   发表时间:2008-01-24  
allenBen 写道
最好就是尽量少用Ajax 因为还不成熟,框架的Bug也太多

[url=http://www.gwteasy.cn][/url]小蜗牛娱乐平台
javascript 写的相信吗?纯的ajax有bug吗?
0 请登录后投票
论坛首页 Web前端技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics