学习历史记录管理

history对象

history对象是window对象的属性,因此,每一个浏览器窗口、每一个标签页和每一个框架,都有自己的history对象(这个特别重要,一开始 学习的时候,我以为整个浏览器就只有一个history对象).出于安全方面的考虑,我们是没有办法知道用户访问过的页面列表,但是可以在不知道实际 url的情况下进行向前和向后跳转.
如下图表显示的是将会讲到的属性和方法

132007_oUoQ_1039981.png

属性

  1. length
    保存历史记录的数量.对于加载到窗口标签页和框架中的第一个页面而言,history.length = 1(MDN上的文档说值为1,但是《JavaScript高级程序设计(第3版)》说它的值为0,我在firefox 38 和chrome 42下测试,history.length = 1)

  2. state
    保存着传递给pushState()或则replaceState()的第一个参数的一个副本(查看《JavaScript权威指南(第6版)》644页的"结构性复制").这个值,也可以通过popstate事件的event.state属性访问到

方法

1. back()
  在历史列表里后退一次,对于加载到窗口 标签页和框架中的第一个页面而言,也就是history.length=1时,调用此方法无效,也不会产生异常

back()=点击后退按钮=go(-1)

2. forward()

  在历史列表里前进一次,对于加载到窗口 标签页和框架中的第一个页面而言,也就是history.length=1时,调用此方法无效,也不会产生异常

 forward()=点击前进按钮=go(1)

3. go()
  传入的数值是相对于当前历史记录的位置,数值越界的话无效,也不会产生异常,不传入任何参数或则传入参数为非数值时无效(《JavaScript高级程序设计(第3版)》在215页提到go()方法支持字符串参数,而MDN说IE才支持字符串参数)

4. pushState(x, y, z)
  x是一个JavaScript对象(任何可以被序列化的对象,实际上,传递给x的对象的类型很广),
  y是一个可选的字符串标题(我测试过,这个参数在firefox38和chrome42下看不到效果,MDN上说firefox会忽略这个参数)
  z是一个URL,通常,可以用它来指定hash片段
  来看如下的测试(在firebug中进行)

location.href
 >> "http://localhost:63333/NumberGuessingGame/test.html"
 location.pathname
 >> "/NumberGuessingGame/test.html"
 history.pushState({page:1},'','#page=1')
 >> undefined
 location.href
 >> "http://localhost:63333/NumberGuessingGame/test.html#page=1"
 location.pathname
 >> "/NumberGuessingGame/test.html"
 history.pushState({page:1},'','/#page=1')
 >> undefined
 location.href
 >> "http://localhost:63333/#page=1"
 location.pathname
 >> "/"

  可以看到z参数中的内容,原本只是简单的添加到localtion.pathname的末尾,但是,如果添加上/字符,那么pathname就会被替换掉(注意,通过这个方法修改hash的值,不会触发hashchange事件)

5. replaceState(x, y, z)
  与pushState()方法基本一致,但是它不是将新的历史记录添加到历史列表中,而是用新的历史记录替换掉当前的历史记录  

事件

1. popstate

属性类型描述
target 只读EventTarget浏览器上下文,就是window对象
type 只读DOMString事件的类型.
bubbles 只读boolean事件正常情况下冒泡吗?
cancelable 只读boolean可以取消事件吗?
state 只读any当前历史条目的state对象(如果设置了的话).

当当前的历史条目改变的时候,就会触发popstate事件.如果历史条目是通过pushState()或则replaceState()来设置的,那么事件处理程序中event.state会包含一条历史条目的state对象的副本
但是pushState()和replaceState()并不会触发popstate和hashchange事件,实际上, 是通过按下前进后退按钮或则history.back()来触发的.
请看如下测试
   测试页面为:

    <!DOCTYPE html>
    <html>
        <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1"/>
        <title></title>
    </head>
    <body>
        <script>
            "use strict";
            window.onpopstate = function () {
                console.log('触发popstate');
            };
            window.onhashchange = function () {
                console.log('触发hashchange');
            };
        </script>
        </body>
    </html>

测试结果

    history.pushState({page:1},'','#page=1')
    >> undefined
    location.href
    >> "http://localhost:63333/NumberGuessingGame/test.html#page=1"
    # 很明显,虽然url改变了,但是没有触发hashchange和popstate事件
    history.back()
    >> 触发popstate
    >> undefined
    >> 触发hashchange
    location.href
    >> "http://localhost:63333/NumberGuessingGame/test.html"
    #这下触发了,接下来测试是用来location对象来操作
    location.hash='#page=2'
    >> 触发popstate
    >> "#page=2"    
    >> 触发hashchange
    location.href
    >> "http://localhost:63333/NumberGuessingGame/test.html#page=2"

通过测试,可以看到popstate和hashchange触发条件的不同,而且,popstate先于hashchange被触发.
实际上,通 过pushState()和replaceState()修改了URL甚至不会产生相应的跳转(例如,通过修改location对象的属性值(除了 hash属性),都会立即导致浏览器跳转到相应的URL),在这种情况下,想要实现跳转只能刷新一下页面,或则回退一次历史记录在前进一次历史记录.


管理历史记录的两种方法

  1. 利用location.hash属性和hashchange事件

  2. 利用pushState()或则replaceState()方法和popstate事件

那么,我们该用哪种方法呢?使用第一种的话,确实比较简单,而且浏览器在HTML5标准化之前就支持这种技术了.我觉得差别不大,更看个人喜好和需求,更觉第二种方法更重量级一些.接下来,我展示一下通过两种不同的技术实现一个管理状态的功能吧!

加入,我们有一个如下的对象需要保存

{
    bookName: 'SegmentFault',
    author: 'tcstory',
    date: '2015/05/17'
}

通过第一种方法来保存:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1"/>
        <title></title>
    </head>
<body>
    <script>
    "use strict";
    var book = {
        bookName: 'SegmentFault',
        author: 'tcstory',
        date: '2015/05/17'
    };

    var saveBook = function () {
    var _temp;
    _temp = 'bookName=' + book.bookName;
    _temp = _temp + '&author=' + book.author;
    _temp = _temp + '&date=' + book.date;
    location.hash =_temp;
};
    </script>
</body>
</html>

打开页面后,在控制台进行如下测试

saveBook()
>> undefined
location.href
>> "http://localhost:63333/NumberGuessingGame/test.html#bookName=SegmentFault&author=tcstory&date=2015/05/17"

可以看到,保存的内容在URL中体现出来了.

现在换第二种方法:

使用的页面

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1"/>
    <title></title>
</head>
<body>
<script>
    "use strict";
    var book = {
        bookName: 'SegmentFault',
        author: 'tcstory',
        date: '2015/05/17'
    };

    var saveBook = function () {
        history.replaceState(book, '', '');
    };
</script>
</body>
</html>

在终端中进行如下测试

saveBook()
>> undefined
history.state
>> Object { bookName="SegmentFault",  author="tcstory",  date="2015/05/17"}

额,我更喜欢后面一种~!感觉更直观~!

参考资料:
https://developer.mozilla.org/en-US/docs/Web/API/History
https://developer.mozilla.org/en-US/docs/Web/Events/popstate


update: 2015.06.13

由于调用pushState()和replaceState()不会主动触发任何事件,这就导致了使用这两个方法难以保证状态的一致性,比如说,你以为你自己在这个页面,但是由于调用了那两个方法,你自己实际上是在另一个页面了,你却不知道.所以,我感觉这两个方法没有多大的用处.

转载于:https://my.oschina.net/tcstory/blog/466354

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值