关于history的一点心得

浏览器上的window.history就是记录页面的历史记录的,在浏览器上打印history对象,会有如下:

History {pushState: ƒ, replaceState: ƒ, length: 7, scrollRestoration: "auto", state: null}

history.length

length是指当前浏览过多少个页面,无论你是执行后退还是前进一页,history都是不变的,除非在当前页面新打开一个链接,那么history就会加一。

history.pushState

history.pushState(State,Title,Url),不跳转,新增一条历史记录,当前页面的url会变成Url,但是不会刷新当前页面,如果此时新打开一个页面,后退会去到Url链接,但页面内容还是url的内容,再后退就会去到url链接,内容不变,就是url的内容。
需要注意的是,history.pushState的Url不能跨域,否则会报错。

history.replaceState

history..replaceState(State,Title,Url),不跳转,修改浏览历史中当前纪录,当前页面url的历史记录会被替换成指定的Url,当前页面的url会变成Url,直接替换掉原来的url,相当于原来的url已经不存在,但是不会刷新当前页面,如果此时新打开一个页面,后退会去到Url链接,但页面内容会改变成Url的内容,再后退就没有可后退的链接了。
需要注意的是,history.replaceState的Url不能跨域,否则会报错。

location.replace

location.replace(url) 会跳转至指定页面,当前页面url的历史记录不会保留,相当于替换了当前的历史记录

location.href

location.href:跳转至指定页面,当前页面url的历史记录会保留

window.onpopstate

每当同一个文档的浏览历史(即history对象)出现变化时,就会触发popstate事件。仅仅调用pushState方法或replaceState方法 ,并不会触发该事件,只有用户点击浏览器倒退按钮和前进按钮,或者使用JavaScript调用back、forward、go方法时才会触发。使用的时候,可以为popstate事件指定回调函数。这个回调函数的参数是一个event事件对象,它的state属性指向pushState和replaceState方法为当前URL所提供的状态对象(即这两个方法的第一个参数state)。如:

history.pushState({title:"login"}, "login", "/login");
window.onpopstate = function (event) {
   if(event.state) {
        var state = event.state.title;
        switch(state) {
           case "login":.............;break;
           case "join" :.............;break;
        }
     }
};
// 或者
window.addEventListener("popstate", function(event){
    if(event.state) {
        var state = event.state.title;
        switch(state) {
           case "login":.............;break;
           case "join" :.............;break;
        }
     }
}, false);

上面代码中的event.state,就是通过pushState和replaceState方法,为当前URL绑定的state对象。这个state对象也可以直接通过history对象读取history.state。

实践

最近做的一个需求是这样的:先由中转页a跳去目标页面b,按回退按钮,跳去中间后台配置页面b1,再按回退按钮跳去中间后台配置页面b2,以此下去,只到跳转完所有后台配置的页面,最终跳回目标页面b,再按返回退出所有页面。

用history来解释的话就是:

a->b->back->a->b1->back->b2->...->back->b->back->退出

用上面的知识来解决就是

a->b,在a页面,获取跳转url的b页面链接,替换参数,改变a链接成a*,即将a的历史记录修改成a*,执行
history.replaceState(null, document.title, a*);window.location.href = b;
回退,此时到a*,获取后台配置,执行
window.location.href = b1;
回退,此时到a*,获取后台配置,执行
window.location.href = b2;
....
后退回到a*,最后回到b,执行
window.location.replace(b);
再后退,退出页面

以上就是利用history和location解决的一个简单示例,其他的应用还可以是改变一个页面的url而不用刷新页面等。

外篇

pageshowpagehide 事件

手机上的浏览器有一个特性,名叫“往返缓存”(back-forward cache,或bfcache),可以在用户使用浏览器的“后退”和“前进”按钮时加快页面的转换速度。这个缓存中不仅保存着页面数据,还保存了DOM和JavaScript的状态;实际上是将整个页面都保存在了内存里。如果页面位于bfcache中,那么再次打开该页面就不会触发load事件。尽管由于内存中保存了整个页面的状态,不触发load事件也不应该会导致什么问题,但为了更形象地说明bfcache的行为,Firefox还是提供了一些新事件。 第一个事件就是pageshow,这个事件在页面显示时触发,无论页面是否来自bfcache。在重新加载页面中,pageshow会在load事件触发后触发;而对于bfcache中的页面,pageshow会在页面状态完全恢复的那一刻触发。
1)load 和 unload 事件监听web页面的进入和离开,一般用于页面的首次加载、刷新和关闭等操作的监听;
2)pageshowpagehide 事件多用于监听浏览器的前进和后退等。

pageshow和load区别:
pageshow 事件类似于 load 事件,load 事件在页面第一次加载时触发, pageshow 事件在每次加载页面时触发,即 load 事件在页面从浏览器缓存中读取时不触发。

一般情况下,移动端浏览器会将当前已访问页面存入缓存中,缓存中保存着页面数据,DOM和js的状态,前进和后退操作时直接从浏览器缓存中读取页面内容,而不进行页面刷新,所以监听前进和后退操作时可用pageshow事件。

window.performance对象

performance.navigation.type是一个无符号短整型,接口呈现了如何导航到当前文档的信息。它有四种type类型:
1、TYPE_NAVIGATE (0):当前页面是通过点击链接,书签和表单提交,或者脚本操作,或者在url中直接输入地址,type值为0。
2、TYPE_RELOAD (1):点击刷新页面按钮或者通过Location.reload()方法显示的页面,type值为1:。
3、TYPE_BACK_FORWARD (2):页面通过历史记录和前进后退访问时。type值为2。
4、TYPE_RESERVED (255): 任何其他方式,type值为255。
所以type为2可以作为页面后退或者前进时的一个判断依据。

window.addEventListener('pageshow', (e) => {
  if (e.persisted || (window.performance && window.performance.navigation.type == 2)) {
    // 页面后退或者前进时刷新页面
    location.reload()
  }

参数教程

  1. history.pushState无刷新改变url
  2. 原HTML5历史状态管理history API-pushState/replaceState与popstate事件
  3. pageshow和pagehide应用场景
  4. 移动端返回强制刷新页面pageshow事件persisted总为false解决方案

推荐阅读更多精彩内容