history那些事

history对象保存着用户上网的历史记录,它是window对象的属性。但出于安全方面的考虑,开发人员无法得知用户浏览过的URL。

window.history.length

返回浏览器历史列表中的URL数量,历史记录栈中共有多少页。

window.history.state

此属性用于储存window.history.pushStatewindow.history.replaceState的data参数。

window.history.go(n)

在用户的历史记录里任意跳转,可以向前也可以向后。负数表示向后跳转,正数表示向前跳转。也可以传递字符串,浏览器会跳转到历史记录中包含该字符串的第一个位置。如果输入是0的话,会刷新页面。

window.history.back()

向后退一页。

window.history.forward()

向前进一页。

window.history.pushState(data, title [, url])

向history堆栈顶部添加一条新的记录,会改变URL但不会刷新页面。

data - 对象,注意必须序列化,与URL相对应,onpopstate触发时会作为参数传入,比如要触发对应的ajax,可以把相应的参数放入data中。

title - 标题,暂时这个参数是被忽略的,将来可能会有用。

url - 浏览器不会在调用pushState()方法后加载该地址,但之后可能会试图加载,如用户重启浏览器。新的URL不一定是绝对路径: 如果是相对路径,它将以当前URL为基准;传入的URL与当前URL应该是同源的,否则,pushState()会抛出异常。该参数是可选的;不指定的话则为文档当前URL。

window.onpopstate

当浏览器前进(go或浏览器的前进键)或是后退(back或浏览器的后退键)时,均会触发这个事件,传入url相对应的data参数(在event.state中)

15-1

window.history.replaceState(data, title [, url])

replaceState()操作类似于pushState(),不同之处在于replaceState()方法会修改当前历史记录条目而并非创建新的条目。

看一个官方示例,就懂了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
window.onpopstate = function(event) {
console.log("location: " + document.location + ", state: " + JSON.stringify(event.state));
};
// 添加并激活一个历史记录条目 http://example.com/example.html?page=1, 条目索引为1
history.pushState({page: 1}, "title 1", "?page=1");
// 添加并激活一个历史记录条目 http://example.com/example.html?page=2, 条目索引为2
history.pushState({page: 2}, "title 2", "?page=2");
// 修改当前激活的历史记录条目 http://ex..?page=2 变为 http://ex..?page=3, 条目索引为3
history.replaceState({page: 3}, "title 3", "?page=3");
// "location: http://example.com/example.html?page=1, state: {"page":1}"
history.back();
// "location: http://example.com/example.html, state: null"
history.back();
// "location: http://example.com/example.html?page=3, state: {"page":3}"
history.go(2);

现在我们的单页应用都是离线化的,或者说只通过少量ajax向后台请求数据完成页面渲染,这样就会产生一个问题,URL不会变化,如果用户需要返回上一页将无法返回。

为了可访问性,ajax内容改变后通常修改URL的hash值(赋值location.hash,触发onhashchange(IE8+))事件,不支持只能轮询。SEO很不友好,Twitter和Google约定了使用#!xxx(即hash第一个字符为!),对搜索引擎进行支持。

这里顺便再提一下url的hash值,也就是所谓的锚点,在相应标签的href中添加”#+位置名称”,当浏览器读取带”#+位置名称”的URL后,可自动滚动到相应标签的可视区域,实现快速定位,浏览器在发生HTTP请求不会附带锚点内容,其只对浏览器起作用。锚点的本质就是修改容器的滚动高度。

再扯回来,对于这样的场景就应该采用ajax + history.pushState,每当页面发生ajax时,将当前页面信息与相应url推入浏览器的历史记录栈,一旦发生回退,触发onpopstate事件,取出event.state,再进行ajax查询,当然直接输入相应的url,也要能渲染出相应的页面。

参考资料

Manipulating the browser history

ajax与HTML5 history pushState/replaceState实例

使用ajax和history.pushState无刷新改变页面URL