首页 > 编程笔记 > JavaScript笔记 > JS BOM

JS history对象详解

history 对象存储了库互动浏览器的浏览历史,通过 window 对象的 history 属性可以访问该对象,实际上 history 属性仅存储最近访问的、有限条目的 URL 信息。

在 HTML5 之前,为了保护客户端浏览信息的安全和隐私,history 对象禁止 JavaScript 脚本直接操作这些访问信息。不过 HTML5 新增了一个 History API,该 API 允许用户通过 JavaScript 管理浏览器的历史记录,实现无刷新更改浏览器地址栏的地址,配合 History + Ajax 可以设计不需要刷新页面的跳转。

操作历史记录

在历史记录中后退

window.history.back();1
这行代码等效于在浏览器的工具栏上单击“返回”按钮。

在历史记录中前进

window.history.forward();1
这行代码等效于浏览器中单击“前进”按钮。

移动到指定的历史记录点

使用 go() 方法从当前会话的历史记录中加载页面。当前页面位置索引值为 0,上一页就是 -1,下一页为 1,以此类推。
window.history.go(-1);  //相当于调用 back()
window.history.go(1);  //相当于调用forward()

length 属性

使用 length 属性可以了解历史记录栈中一共有多少页。
var num = window.history.length;

添加和修改历史记录条目

HTML5 新增 history.pushState() 和 history.replaceState() 方法,允许用户逐条添加和修改历史记录条目。

使用 history.pushState() 方法可以改变 referrer 的值,而在调用该方法后创建的 XMLHttpRequest 对象会在 HTTP 请求头中使用这个值。referrer 的值则是创建 XMLHttpRequest 对象时所处的窗口的 URL。

【示例】假设 http://123.com/foo.html 页面将执行下面 JavaScript 代码。
var stateObj = {foo : "bar"};
history.pushState (stateObj, "page 2", "bar.html");
这时浏览器的地址栏将显示 http://123.com/bar.html,但不会加载 bar.html 页面,也不会检查 bar.html 是否存在。

如果现在导航到 http://123.com/ 页面,然后单击“后退”按钮,此时地址栏会显示 http://123.com/bar.html,并且会触发 popstate 事件,该事件中的状态对象会包含 stateObj 的一个拷贝。

如果再次单击“后退”按钮,URL 将返回 http://123.com/foo.html,文档将触发另一个 popstate 事件,这次的状态对象为 null,回退同样不会改变文档内容。

pushState() 方法

pushState() 方法包含 3 个参数,简单说明如下: 浏览器不会在调用 pushState() 方法后加载该地址,如果不指定则为文档当前 URL。

调用 pushState() 方法类似于设置 window.location='#foo',它们都会在当前文档内创建和激活新的历史记录条目。但 pushState() 有自己的优势。
pushState() 方法永远不会触发 hashchange 事件

replaceState() 方法

history.replaceState() 与 history.pushState() 用法相同,都包含 3 个相同的参数。不同之处是:pushState() 是在 history 栈中添加一个新的条目,replaceState() 是替换当前的记录值。例如,history 栈中有两个栈块,一个标记为 1,另一个标记为 2,现在有第 3 个栈块,标记为 3。当执行 pushState() 时,栈块 3 将被添加栈中,栈就有 3 个栈块了;而当执行 replaceState() 时,将使用栈块 3 替换当前激活的栈块 2,history 的记录条数不变。也就是说,pushState() 会让 history 的数量加 1。

为了响应用户的某些操作,需要更新当前历史记录条目的状态对象或 URL 时,使用 replaceState() 方法会特别合适。

popstate 事件

每当激活的历史记录发生变化时,都会触发 popstate 事件。如果被激活的历史记录条目是由 pushState() 创建,或者是被 replaceState() 方法替换的,popstate 事件的状态属性将包含历史记录的状态对象的一个拷贝。

当浏览会话历史记录时,不管是单击浏览器工具栏中的“前进”或者“后退”按钮,还是使用 JavaScript 的 history.go() 和 history.back() 方法,popstate 事件都会被触发。

读取历史状态

在页面加载时,可能会包含一个非空的状态对象。这种情况是会发生的,例如,如果页面中使用 pushState() 或 replaceState() 方法设置了一个状态对象,然后重启浏览器。当页面重新加载时,页面会触发 onload 事件,但不会触发 popstate 事件。但是,如果读取 history.state 属性,会得到一个与 popstate 事件触发时一样的状态对象。

可以直接读取当前历史记录条目的状态,而不需要等待 popstate 事件。
var currentState = history.state;

案例:设计无刷新导航

本例设计一个无刷新页面导航,在首页(index.html)包含一个导航列表,当用户单击不同的列表项目时,首页(index.html)的内容容器(<div id="content">)会自动更新内容,正确显示对应目标页面的 HTML 内容,同时浏览器地址栏正确显示目标页面的 URL(但是首页并没有被刷新),而不是仅显示目标页面。显示效果如图所示。

 

在浏览器工具栏中单击“后退”按钮,浏览器能够正确显示上一次单击的链接地址,虽然页面并没有被刷新,同时地址栏中正确显示上一次浏览页面的 URL,如下图所示。如果没有 History API 支持,使用 Ajax 实现异步请求时,工具栏中的“后退”按钮的是无效的。


但是,如果在工具栏中单击“刷新”按钮,则页面将根据地址栏的 URL 信息重新刷新页面,显示独立的目标页面,效果如下图所示。


此时,如果再单击工具栏中的“后退”和“前进”按钮,会发现导航功能失效。页面总是显示目标页面,如下图所示。这说明使用 History API 控制导航与浏览器导航功能存在差异,一个是 JavaScript 脚本控制,一个是系统自动控制。

【操作步骤】

1) 设计首页(index.html)。新建文档,保存为 index.html,构建 HTML 导航结构。
<h1>History API 示例</h1>
<ul id="menu">
    <li><a href="news.html">News</a></li>
    <li><a href="about.html">About</a></li>
    <li><a href="contact.html">Contact</a></li>
</ul>
<div id="content">
    <h2>当前页内容:index.html</h2>
</div>

2) 本例使用 jQuery 作为辅助操作,因此在文档头部位置导入 jQuery 框架。
<script src="jquery/jquery-1.11.0.js" type="text/javascript"></script>

3) 定义异步请求函数。该函数根据参数 url 值,异步加载目标地址的页面内容,把它置入内容容器(<div id="content">)中,并根据第 2 个参数 addEntry 的值执行额外操作。如果第 2 个参数值为 true,则使用 history.pushState() 方法把目标地址推入浏览器历史记录堆栈中。
function getContent (url, addEntry) {
    $.get (url).done(function (data) {  //异步请求
        $('#content').html (data);  //动态加载目标页面
        if (addEntry == true) {
            history.pushState(none, none, url);  //把目标地址推入浏览器历史记录堆栈中
        }
    });
}

4) 在页面初始化事件处理函数中,为每个导航链接绑定 click 事件,在 click 事件处理函数中调用 getContent() 函数,同时阻止页面的刷新操作。
$ (function () {
    $ ('#menu a').on ('onclick', function (e) {
        e.preventDefault ();  //阻止页面刷新操作
        var href = $ (this).attr('href');
        getContent (href, true);  //执行页面内容更新操作
        $ ('#menu a').removeClass ('active');
        $ (this).addClass ('active');
    });
});

5) 注册 popstate 事件,跟踪浏览器历史记录的变化,如果发生变化,则调用 getContent() 函数更新页面内容,但是不再把目标地址添加到历史记录堆栈中。
window.addEventListener ("popstate", function (e) {
    getContent (location.pathname,false);
});

所有教程

优秀文章