1. 程式人生 > >移動端H5頁面返回並且重新整理頁面(BFcache)

移動端H5頁面返回並且重新整理頁面(BFcache)

專案中的需求:點選瀏覽器中的返回按鈕,要讓頁面重新載入資源。因為這部分的資源每次去載入的內容都不一樣,如果返回的時候,還是看到原先的內容,那做這個內容塊的意義就很小了;而如果使用者看完了這部分內容,再返回來的時候,這個地方換成了新的內容,這樣就能體現這部分的價值了。

而對於瀏覽器來說,大部分瀏覽器的返回是直接使用快取的,不會執行任何的javascript程式碼。原因:部分瀏覽器在後退時不會觸發onload事件,這是HTML5世代瀏覽器新增的特性之一——Back-Forward Cache(簡稱bfcache)

什麼是bfcache?

bfcache,即back-forward cache,可稱為“往返快取”,可以在使用者使用瀏覽器的“後退”和“前進”按鈕時加快頁面的轉換速度。這個快取不僅儲存頁面資料,還儲存了DOM和JS的狀態,實際上是將整個頁面都儲存在記憶體裡。如果頁面位於bfcache中,那麼再次開啟該頁面就不會觸發onload事件

pageshow事件

這個事件在使用者瀏覽網頁時觸發,pageshow 事件類似於 onload 事件,onload 事件在頁面第一次載入時觸發, pageshow 事件在每次載入頁面時觸發,即 onload 事件在頁面從瀏覽器快取中讀取時不觸發。

pagehide事件

該事件會在使用者離開網頁時觸發。離開網頁有多種方式。如點選一個連結,重新整理頁面,提交表單,關閉瀏覽器等。pagehide 事件有時可以替代 unload事件,但 unload 事件觸發後無法快取頁面。

persisted屬性

pageshow事件和pagehide事件的event物件還包含一個名為persisted的布林值屬性。

  對於pageshow事件,如果頁面是從bfcache中載入的,則這個屬性的值為true;否則,這個屬性的值為false。  對於pagehide事件,如果頁面在解除安裝之後被儲存在bfcache中,則這個屬性的值為true;否則,這個屬性的值為false。

不同的瀏覽器在對當前視窗‘開啟’歷史記錄中的前一個頁面的表現上並不統一,這和瀏覽器的實現以及頁面本身的設定有關係。

解決方案:

javascript監聽pageshow事件阻止頁面進入bfcache

 window.addEventListener('pageshow', function (e) {
     if (e.persisted) {
         window.location.reload()
     }
})

在uc和微信中測試通過,但是在某些安卓手機自帶的瀏覽器中無效。

javascript監聽pagehide事件阻止頁面進入bfcache

window.addEventListener('pagehide', function (e) {
    var dom = document.body;
    dom.children.remove();
    setTimeout(function () {
        dom.appendChild("<script type='text/javascript'>window.location.reload();<\/script>");
    });
});

設定meta標籤,清除頁面快取

<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />

Cache-Control指定請求和響應遵循的快取機制。在請求訊息或響應訊息中設定Cache-Control並不會修改另一個訊息處理過程中的快取處理過程。請求時的快取指令包括no-cache、no-store、max-age、max-stale、min-fresh、only-if-cached,響應訊息中的指令包括public、private、no-cache、no-store、no-transform、must-revalidate、proxy-revalidate、max-age。各個訊息中的指令含義如下Public指示響應可被任何快取區快取Private指示對於單個使用者的整個或部分響應訊息,不能被共享快取處理。這允許伺服器僅僅描述當用戶的部分響應訊息,此響應訊息對於其他使用者的請求無效no-cache指示請求或響應訊息不能快取no-store用於防止重要的資訊被無意的釋出。在請求訊息中傳送將使得請求和響應訊息都不使用快取。max-age指示客戶機可以接收生存期不大於指定時間(以秒為單位)的響應min-fresh指示客戶機可以接收響應時間小於當前時間加上指定時間的響應max-stale指示客戶機可以接收超出超時期間的響應訊息。如果指定max-stale訊息的值,那麼客戶機可以接收超出超時期指定值之內的響應訊息。注:有些情況下設定清除快取也沒有起到作用,我自己做的這個h5頁面就沒有起到效果。具體情況還是要具體分析。

我遇到的情況:

<div class="content">
     <iframe id="iframe" src="https://cpu.baidu.com/xx/xx/xxx" frameborder="no" scrolling="no"></iframe>
</div>

這個iframe中的地址每次重新整理頁面都會有不同的內容推送給使用者。進入iframe中的內容之後,按返回按鈕返回來想進行頁面自動重新整理,為的就是讓使用者看到新的內容。

做法:

使用pageshow進行整個頁面重新整理

 window.addEventListener('pageshow', function (e) {
     if (e.persisted) {
         window.location.reload()
     }
 })

這樣可以實現。

後面又覺得不妥,沒有因為這個小部分而進行整個頁面重新整理,想到了另一種思路:因為這個iframe中的內容是動態的,可以對其進行定時器設定,如下:

 let iframe = document.getElementById('iframe')
 setInterval(() => {
     iframe.setAttribute("src", "https://cpu.baidu.com/xx/xx/xx");
 },15000)

這樣也可以實現自己的功能。

最後可以結合一下:

let iframe = document.getElementById('iframe')
window.addEventListener('pageshow', function (e) {
    if (e.persisted) {
        iframe.setAttribute("src", "https://cpu.baidu.com/xx/xx/xx");
    }
})

這樣做也有好處,可以避免使用定時器,對網頁的效能也是比較好。但是這個方法在返回的時候,可以看到iframe裡面內容的重新載入,會有一個時間間隙。