前進(jìn)之前與后退之后-pageshow&pagehide

需求背景

一個(gè)頁面A需要記錄在頁面點(diǎn)擊某個(gè)鏈接B時(shí)的時(shí)間time1,與后退返回該頁面時(shí)的時(shí)間time2募书,得到中間的時(shí)間差time2-time1折剃。
此處的難點(diǎn)在于:
1、點(diǎn)擊跳出A的B是不確定的殖蚕,有可能點(diǎn)擊的是廣告(點(diǎn)擊的是廣告轿衔,則幾乎很難監(jiān)聽到點(diǎn)擊廣告的事件),有可能是一個(gè)頁面鏈接(頁面鏈接有可能非常多睦疫,不可能每個(gè)鏈接都加一個(gè)監(jiān)聽事件)害驹;
2、記錄離開頁面前的時(shí)間蛤育,與返回頁面的時(shí)間宛官,離開頁面有可能是在當(dāng)前頁面刷新打開頁面,有可能是新開窗口打開瓦糕,情況有多種底洗。

解決思路

巧用pagehidepageshow咕娄,document.hidden亥揖,visibilitychange組合實(shí)現(xiàn)。

pageshowpagehide 事件

手機(jī)上的瀏覽器有一個(gè)特性,名叫“往返緩存”(back-forward cache费变,或bfcache)摧扇,可以在用戶使用瀏覽器的“后退”和“前進(jìn)”按鈕時(shí)加快頁面的轉(zhuǎn)換速度。這個(gè)緩存中不僅保存著頁面數(shù)據(jù)挚歧,還保存了DOM和JavaScript的狀態(tài)扛稽;實(shí)際上是將整個(gè)頁面都保存在了內(nèi)存里。如果頁面位于bfcache中滑负,那么再次打開該頁面就不會(huì)觸發(fā)load事件在张。盡管由于內(nèi)存中保存了整個(gè)頁面的狀態(tài),不觸發(fā)load事件也不應(yīng)該會(huì)導(dǎo)致什么問題矮慕,但為了更形象地說明bfcache的行為帮匾,F(xiàn)irefox還是提供了一些新事件。 第一個(gè)事件就是pageshow凡傅,這個(gè)事件在頁面顯示時(shí)觸發(fā)辟狈,無論頁面是否來自bfcache。在重新加載頁面中夏跷,pageshow會(huì)在load事件觸發(fā)后觸發(fā)哼转;而對(duì)于bfcache中的頁面,pageshow會(huì)在頁面狀態(tài)完全恢復(fù)的那一刻觸發(fā)槽华。
1)load 和 unload 事件監(jiān)聽web頁面的進(jìn)入和離開壹蔓,一般用于頁面的首次加載、刷新和關(guān)閉等操作的監(jiān)聽猫态;
2)pageshowpagehide 事件多用于監(jiān)聽瀏覽器的前進(jìn)和后退等佣蓉。

1、pageshow和load區(qū)別:
pageshow 事件類似于 load 事件亲雪,load 事件在頁面第一次加載時(shí)觸發(fā)勇凭, pageshow 事件在每次加載頁面時(shí)觸發(fā),即 load 事件在頁面從瀏覽器緩存中讀取時(shí)不觸發(fā)义辕。

一般情況下虾标,移動(dòng)端瀏覽器會(huì)將當(dāng)前已訪問頁面存入緩存中,緩存中保存著頁面數(shù)據(jù)灌砖,DOM和js的狀態(tài)璧函,前進(jìn)和后退操作時(shí)直接從瀏覽器緩存中讀取頁面內(nèi)容,而不進(jìn)行頁面刷新基显,所以監(jiān)聽前進(jìn)和后退操作時(shí)可用pageshow事件蘸吓。

觸發(fā)時(shí)間:load先觸發(fā),pageshow后觸發(fā)撩幽。

2库继、查看是否讀取緩存:
為了查看頁面是直接從服務(wù)器上載入還是從緩存中讀取,你可以使用 Event 對(duì)象的 persisted 屬性來判斷。 如果頁面從瀏覽器的緩存中讀取該屬性返回 ture宪萄,否則返回 false

3舅桩、示例:

window.addEventListener('pageshow', function(event) {
    console.log(event.persisted);
})

4、pagehide和unload事件的區(qū)別:
pagehide 事件類似于 unload 事件雨膨,在用戶離開網(wǎng)頁時(shí)觸發(fā)(如點(diǎn)擊一個(gè)鏈接、刷新頁面读串、提交表單聊记、關(guān)閉瀏覽器、前進(jìn)恢暖、后退等)排监。
頁面緩存:pagehide觸發(fā)可以緩存頁面,但unload 事件觸發(fā)后無法緩存杰捂。
觸發(fā)時(shí)間:pagehide先觸發(fā)舆床,unload后觸發(fā)。

2嫁佳、查看是否讀取緩存:
同pageshow

pageshow挨队,pagehide兼容情況:基本移動(dòng)端上用都兼容


image.png

問題:但是有時(shí)候在一些機(jī)型中event. persisted判斷并不準(zhǔn)確,所以可以引用window.performance.navigation.type做兼容處理蒿往。

window.performance對(duì)象

performance.navigation.type是一個(gè)無符號(hào)短整型盛垦,接口呈現(xiàn)了如何導(dǎo)航到當(dāng)前文檔的信息。它有四種type類型:
1瓤漏、TYPE_NAVIGATE (0):當(dāng)前頁面是通過點(diǎn)擊鏈接腾夯,書簽和表單提交,或者腳本操作蔬充,或者在url中直接輸入地址蝶俱,type值為0。
2饥漫、TYPE_RELOAD (1):點(diǎn)擊刷新頁面按鈕或者通過Location.reload()方法顯示的頁面榨呆,type值為1:。
3趾浅、TYPE_BACK_FORWARD (2):頁面通過歷史記錄和前進(jìn)后退訪問時(shí)愕提。type值為2。
4皿哨、TYPE_RESERVED (255): 任何其他方式浅侨,type值為255。
所以type為2可以作為頁面后退或者前進(jìn)時(shí)的一個(gè)判斷依據(jù)证膨。

window.addEventListener('pageshow', (e) => {
  if (e.persisted || (window.performance && window.performance.navigation.type === 2)) {
    // 頁面后退或者前進(jìn)時(shí)操作
  }

document.hidden屬性

頁面可見性判斷:document.hiddenvisibilitychange事件如输,當(dāng)前頁面不在視野范圍內(nèi),則會(huì)觸發(fā)visibilitychange事件,并且改變document.hidden的值為true不见,當(dāng)回到頁面視野當(dāng)中澳化,也會(huì)觸發(fā)事件改變document.hidden的值為false。

    // 兼容瀏覽器
    const hidden = 'hidden' in document ? 'hidden' : 'webkitHidden' in document ? 'webkitHidden' : 'mozHidden' in document ? 'mozHidden' : null;
    const event = hidden.replace(/hidden/i, 'visibilitychange');
    document.addEventListener(event, () => {
      console.log('當(dāng)前頁面是否被隱藏:', document[hidden]);
    });

具體實(shí)現(xiàn)

頁面A點(diǎn)擊頁面中的鏈接B跳去新鏈接稳吮,記錄離開A頁面的時(shí)間與返回A頁面的時(shí)間缎谷。
B頁面離開方式:
1、當(dāng)前窗口打開頁面(非跳出型):監(jiān)聽pagehide & document.hidden=true
2灶似、新開窗口打開頁面(跳出型):監(jiān)聽pagehide & document.hidden=true

返回頁面A方式:
1列林、返回后頁面被動(dòng)刷新:監(jiān)聽pageshow
2、返回后頁面不刷新:監(jiān)聽document.hidden=false

終上所述酪惭,為了兼容設(shè)備前進(jìn)后退的多種差異情況希痴,需要融合幾種監(jiān)聽方式,以達(dá)到覆蓋多種情況的效果(經(jīng)測試春感,在安卓版本5砌创,7,10上組合方式都通過測試鲫懒,ios也通過了測試)嫩实。

// 兼容瀏覽器
const hidden = 'hidden' in document ? 'hidden' : 'webkitHidden' in document ?
 'webkitHidden' : 'mozHidden' in document ? 'mozHidden' : null;
const event = hidden.replace(/hidden/i, 'visibilitychange');
document.addEventListener(event, () => {
  if(document[hidden]) {
    // 隱藏:記錄離開時(shí)間
  } else {
    // 顯示:記錄返回時(shí)間
  }
});

window.addEventListener('pageshow', (e) => {
  if (e.persisted || (window.performance && window.performance.navigation.type === 2)) {
    // 頁面后退時(shí)操作:記錄返回時(shí)間
  }
}

window.addEventListener('pagehide', (e) => {
   // 頁面離開時(shí)操作:記錄離開時(shí)間
}

后記

在vue中,如果已經(jīng)創(chuàng)建了Vue示例再實(shí)行監(jiān)聽pageshow時(shí)間的話刀疙,是會(huì)失效的舶赔,所以,需要在未創(chuàng)建Vue示例前監(jiān)聽pageshow事件谦秧,并且可以通過window.postMessage延遲傳遞信息:

window.addEventListener('pageshow', (t) => {
  // persisted:查看頁面是直接從服務(wù)器上載入還是從瀏覽器緩存中讀取,true:緩存讀取
  if (t.persisted || (window.performance && window.performance.navigation.type === 2)) {
    setTimeout(() => {
      window.postMessage('pageshowEvent', window.location.origin);
    }, 2000);
  }
  new Vue({
      el: '#app',
      template: '<Main />',
      components: { Main },
    });
});

// 實(shí)現(xiàn)vue文件中
window.addEventListener('message', (e) => {
   if (e.origin !== window.location.origin && e.data !== 'pageshowEvent') return;
   // 后續(xù)處理
}, false);

參考文章

  1. pageshow和pagehide應(yīng)用場景
  2. 移動(dòng)端返回強(qiáng)制刷新頁面pageshow事件persisted總為false解決方案
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末竟纳,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子疚鲤,更是在濱河造成了極大的恐慌锥累,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,692評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件集歇,死亡現(xiàn)場離奇詭異桶略,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)诲宇,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,482評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門际歼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人姑蓝,你說我怎么就攤上這事鹅心。” “怎么了纺荧?”我有些...
    開封第一講書人閱讀 162,995評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵旭愧,是天一觀的道長颅筋。 經(jīng)常有香客問我,道長输枯,這世上最難降的妖魔是什么议泵? 我笑而不...
    開封第一講書人閱讀 58,223評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮桃熄,結(jié)果婚禮上先口,老公的妹妹穿的比我還像新娘。我一直安慰自己瞳收,他們只是感情好池充,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,245評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著缎讼,像睡著了一般。 火紅的嫁衣襯著肌膚如雪坑匠。 梳的紋絲不亂的頭發(fā)上血崭,一...
    開封第一講書人閱讀 51,208評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音厘灼,去河邊找鬼夹纫。 笑死,一個(gè)胖子當(dāng)著我的面吹牛设凹,可吹牛的內(nèi)容都是我干的舰讹。 我是一名探鬼主播,決...
    沈念sama閱讀 40,091評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼闪朱,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼月匣!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起奋姿,我...
    開封第一講書人閱讀 38,929評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤锄开,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后称诗,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體萍悴,經(jīng)...
    沈念sama閱讀 45,346評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,570評(píng)論 2 333
  • 正文 我和宋清朗相戀三年寓免,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了癣诱。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,739評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡袜香,死狀恐怖撕予,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情困鸥,我是刑警寧澤嗅蔬,帶...
    沈念sama閱讀 35,437評(píng)論 5 344
  • 正文 年R本政府宣布剑按,位于F島的核電站,受9級(jí)特大地震影響澜术,放射性物質(zhì)發(fā)生泄漏艺蝴。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,037評(píng)論 3 326
  • 文/蒙蒙 一鸟废、第九天 我趴在偏房一處隱蔽的房頂上張望猜敢。 院中可真熱鬧,春花似錦盒延、人聲如沸缩擂。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,677評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽胯盯。三九已至,卻和暖如春计露,著一層夾襖步出監(jiān)牢的瞬間博脑,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,833評(píng)論 1 269
  • 我被黑心中介騙來泰國打工票罐, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留叉趣,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,760評(píng)論 2 369
  • 正文 我出身青樓该押,卻偏偏與公主長得像疗杉,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子蚕礼,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,647評(píng)論 2 354