解决浏览器返回页面不刷新的问题

现象

因为 IOS 系统的页面缓存机制,常常会遇到在移动端返回到上一个页面不刷新的状况。css

好比今天在开发微信 H5 页面的时候,在IOS微信内置浏览器中返回上一页时,上一个页面不会被刷新。 而一般在浏览器缓存机制中,在返回上一页的操做中, html/css/js/接口 等动静态资源不会从新请求,可是js会从新加载。但在IOS微信页面中js也会保存上一页面最后执行的状态,不会从新执行js。 使用这种模式的缓存机制能够加快渲染速度,可是部分数据须要常常展现和编辑的状况下会致使不一样步。好比‘详情页’跳转到‘编辑页’,编辑完后再返回到‘详情页’,若是‘详情页’数据展现未进行同步修改那确定是不能接受的。 在webview和5+的混合app模式中,也会遇到这种返回上一个页面不刷新的问题html

产生缘由

浏览器前进/后退缓存前端

这里提到一个概念,浏览器前进/后退缓存(Backward/Forward Cache, BF Cache),固然也有人叫 disk Cache。 BF Cache 是一种浏览器优化, HTML 标准并未指定其如何进行缓存,所以缓存行为是各浏览器各自实现,因此不尽相同。 因为不是 HTTP 缓存,因此经过头文件缓存设置 no-cache 是无效的。固然也不能以 HTTP 缓存机制来理解 BF Cache。ios

解决思路

设置浏览历史当前记录web

//监听后退返回事件 --解决微信返回不刷新问题
pushHistory: function(){
    window.addEventListener("popstate", function(e) {
        self.location.reload();
    }, false);
    var state = {
        title : "",
        url : "#"
    };
    window.history.replaceState(state, "", "#");
},

/** * 页面初始化调用pushHistory,监听popstate事件和执行replaceState() * 当执行replaceState()时,不会触发popstate事件,因此不会重复刷新 * 当在ios微信内置浏览器中执行浏览器前进后退操做时,触发popstate事件,执行location.reload() * 可是在谷歌浏览器中执行浏览器前进后退操做时,不会触发popstate事件!由于不在一个document中了 * 可是若是手动改变URL的哈希值,好比www.baidu.com# 改为 www.baidu.com#1 会触发popstate事件,执行location.reload() * 以上若是有一项不理解或不清晰,请往下看原理深究,你会找到答案 **/
复制代码

原理深究

前端路由实现(history)原理chrome

之前浏览器操做浏览器历史记录主要依据history对象。在它的 proto 继承有 back、forward、go 等函数。 而 HTML5 后新增 popState 来控制浏览历史记录的 api。有能够存储当前历史记录点的 pushState、替换当前历史记录点的 replaceState、和监听历史记录点的 onPopState。api

window.history.pushState(state, title, url)浏览器

  • state (状态对象): 一个js对象,能够用来存储一些简单的数据。值得一提的是若是被激活的历史记录条目是经过 pushState 或 replaceState 调用而生成的,popState事件的state属性包含历史条目的状态对象的副本。能够从 history.state中读取存储的 state。
  • title (标题): 目前被浏览器忽略了,因此一般传入一个空字符串
  • URL (地址): 新的历史记录条目的地址。值得一提的是调用 pushState() 后浏览器并不会当即加载这个 URL,但可能会在用户从新打开浏览器时等某些状况加载这个 URL。而且新 URL 必须与当前 URL 同源,不然会抛出一个异常。 新 URL 可为绝对路径或者是相对路径。

window.history.replaceState(state, title, url)缓存

  • 相同之处是两个API都会操做浏览器的历史记录,而不会引发页面的刷新,也不会去验证这个新条目对应的网页是否存在。
  • 不一样之处在于 pushState 会增长一条新的历史记录,而 replaceState 则会替换当前的历史记录。
  • 两个 API 都绝对不会触发 hashchange 事件,即便新的 URL 与旧的 URL 仅哈希不一样也是如此
  • 若是传递了 stateObj,就会更新当前条目关联的状态对象;若是传递了 url,就会替换当前条目的页面地址和更改浏览器地址栏的地址。

window.onpopstate事件bash

  • 仅在浏览器前进后退操做、history.go/back/forward 调用、hashChange 的时候触发
  • history.pushState 和 history.replaceState 都不会触发这个事件
  • firfox,chrome 在页面首次打开时都不会触发 popstate 事件,可是 safari 会
  • popstate 事件做用范围仅在于一个 document 里面,因为 pushState 和 hashchange 都不会改变网页的内容也就是 document,因此这样的网页里面才能有效使用 popstate。假如咱们输入一个网页,而且在它里面添加了 popstate 回调;而后经过连接跳转的方式转到另一个网页;再点击后退按钮回到第一个网页。这样的状况,第一个网页里面的 popstate 回调,除了有可能由于页面初始化被触发外,浏览器的后退前进是不会触发它的,由于这种方式改变了窗口的 document。可是!!!在 iOS 微信内置浏览器上,重复上述的操做,会触发 onpopstate 事件!,因此咱们才能解决在微信浏览器上页面返回不刷新的问题

pushState 和replaceState 的第一个参数 stateObj,会与第三个参数对应的历史条目绑定在一块,当 popstate 事件触发的时候,意味着有新的历史记录条目被激活,在 popstate 的事件对象里面,有一个 state 属性,会返回这个激活条目关联的 stateObj 对象的拷贝。一个历史记录条目只有当它是被 pushState 建立的,或者用 replaceState 改过的,才可能有关联的 stateObj 对象,因此当某些非这2种条件的历史记录条目被激活的时候,可能拿到的 stateObj 就是 null。

禁止返回上一页的一种方案

/**
* 向历史记录中手动添加一条记录
* 用户选择返回的时候,每次都会消耗一个 history 实体,此时触发 popstate 监听事件,再手动添加一条history实体记录
* 因此用户不管点击多少次都会永远留在这个页面了,固然页面也不会刷新
**/
function pushHistory() {
    window.history.pushState(null, null, "#");
    window.addEventListener("popstate", function (e) {
        console.log(e);
        window.history.pushState(null, null, "#");
    }, false);
}
复制代码

URL中的#

URL 中的 # 就表示的是 URL 的哈希值

  • #表明网页中的一个位置,其右边的字符,就是该位置的标识符。
设置方法:
step1:设置一个锚点<a href="#print">定位到print位置</a>
step2:在页面须要定位的内容加上id="print"。例如:<div id="print"></div> 或者 <a name="print"></a>
测试:step1设置的锚点,step2中id为print的内容会滚动到页面顶端(可观察滚动条的距离)。同时,页面的url末端中会出现 # print的哈希值。
复制代码
  • HTTP请求不包含#
    #号是用来指导浏览器动做的,对服务器端彻底无用。
    在第一个#后面出现的任何字符,都会被浏览器解读为位置标识符。这意味着,这些字符都不会被发送到服务器端。
    访问下面的网址: www.w3cschool.cn/#hello 浏览器实际发出的请求时这样的:

  • 改变#不触发网页重载
    单单改变#后的内容,浏览器只会滚动到相应位置,不会从新加载网页。
    浏览器也不会从新向服务器请求页面

  • 改变#会改变浏览器的访问历史
    每一次改变#后的部分,都会在浏览器的访问历史中增长一个记录,使用"后退"按钮,就能够回到上一个位置。

  • window.location.hash读取#值
    window.location.hash这个属性可读可写。读取时,能够用来判断网页状态是否改变;写入时,则会在不重载网页的前提下,创造一条访问历史记录。

  • onhashchange事件
    这是一个HTML 5新增的事件,当#值发生变化时,就会触发这个事件。IE8+、Firefox 3.6+、Chrome 5+、Safari 4.0+支持该事件。

    // 它的使用方法有三种:
    window.onhashchange = func;
    <body onhashchange="func();">
    window.addEventListener("hashchange", func, false);
    复制代码
  • Google抓取#的机制
    默认状况下,Google的网络蜘蛛忽视URL的#部分。
    可是,Google还规定,若是你但愿Ajax生成的内容被浏览引擎读取,那么URL中可使用"#!",Google会自动将其后面的内容转成查询字符串_escaped_fragment_的值。
    好比,Google发现新版twitter的URL:twitter.com/#!/username
    就会自动抓取另外一个URL:twitter.com/?escaped_fragment=/username 经过这种机制,Google就能够索引动态的Ajax内容。

相关文章
相关标签/搜索