为 Ajax 应用增添前进/后退能力的两种解决方案
2013-02-18
浏览器能够支持在用户访问过的页面间进行前进 / 后退的操作,依赖于内部维持的 history 对象。出于安全性的考虑,浏览器并不允许 JavaScript 脚本对该对象进行增删改之类写操作,而只是可以通过 history. back/forward() 等方法进行访问。既然在页面状态发生变化时,无法通过脚本直接去影响浏览器的历史信息,那么只有通过 URL 的变化来触发浏览器增加一条新的历史记录。这也就是说需要将 Ajax 应用的不同页面状态与 URL 进行一种一对一的映射,并且能够在回退或前进到某一 URL 之时,应用本身能够在页面无刷新的情况下跳转到正确的页面状态。
那么,如何对 Ajax 应用的初始 URL 进行改变,而同时这种变化的切换又不会引起页面的重新加载呢?答案只有一个,那就是借助用于页面内资源片段定位目的的“片段标识符”(fragment identifier),即 URL 中“#”符号后的字符串(hash string)。当浏览器向服务器端请求资源时,片段标识符并不会连同 base URL 一同发往服务器端,而只是在得到服务器返回的结果之后帮助浏览器快速定位到被相应的锚点(anchor)所标识的资源片段,即使无法找个对应的锚点,浏览器也并不会报错。正是基于浏览器的这一特性,构建片段标识符与页面状态之间的映射关系成为了解决此类问题的基础。
目前,除 IE 之外的浏览器都能够将因 hash 字符串改变而产生的新 URL 作为一条新的记录加入到浏览器的历史堆栈中,通过对 window.location.hash 属性的读写,JavaScript 脚本可以获取并设置 hash 字符串,从而间接达到通过脚本了影响浏览器历史记录的目的。这里需要特别指出的是,IE 并不认为有必要将非法片段标识符引发的变化等同于 URL 发生了变化,也便不会进行任何记录历史信息的操作,这时最为常见的一种解决方法是在页面中嵌入一个隐藏 iframe,由于浏览器可以对 DOM 树中 iframe 节点的 src 属性进行历史记录跟踪,这样通过在逻辑上建立一条“页面 URL -- 页面内 iframe URL -- 页面状态”的对应链,同样可以在 IE 中建立片段标识符与页面状态的联系。