美文网首页程序员
前进之前与后退之后-pageshow&pagehide

前进之前与后退之后-pageshow&pagehide

作者: xurna | 来源:发表于2020-08-05 14:16 被阅读0次

需求背景

一个页面A需要记录在页面点击某个链接B时的时间time1,与后退返回该页面时的时间time2,得到中间的时间差time2-time1
此处的难点在于:
1、点击跳出A的B是不确定的,有可能点击的是广告(点击的是广告,则几乎很难监听到点击广告的事件),有可能是一个页面链接(页面链接有可能非常多,不可能每个链接都加一个监听事件);
2、记录离开页面前的时间,与返回页面的时间,离开页面有可能是在当前页面刷新打开页面,有可能是新开窗口打开,情况有多种。

解决思路

巧用pagehidepageshowdocument.hiddenvisibilitychange组合实现。

pageshowpagehide 事件

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

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

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

触发时间:load先触发,pageshow后触发。

2、查看是否读取缓存:
为了查看页面是直接从服务器上载入还是从缓存中读取,你可以使用 Event 对象的 persisted 属性来判断。 如果页面从浏览器的缓存中读取该属性返回 ture,否则返回 false

3、示例:

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

4、pagehide和unload事件的区别:
pagehide 事件类似于 unload 事件,在用户离开网页时触发(如点击一个链接、刷新页面、提交表单、关闭浏览器、前进、后退等)。
页面缓存:pagehide触发可以缓存页面,但unload 事件触发后无法缓存。
触发时间:pagehide先触发,unload后触发。

2、查看是否读取缓存:
同pageshow

pageshow,pagehide兼容情况:基本移动端上用都兼容


image.png

问题:但是有时候在一些机型中event. persisted判断并不准确,所以可以引用window.performance.navigation.type做兼容处理。

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)) {
    // 页面后退或者前进时操作
  }

document.hidden属性

页面可见性判断:document.hiddenvisibilitychange事件,当前页面不在视野范围内,则会触发visibilitychange事件,并且改变document.hidden的值为true,当回到页面视野当中,也会触发事件改变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('当前页面是否被隐藏:', document[hidden]);
    });

具体实现

页面A点击页面中的链接B跳去新链接,记录离开A页面的时间与返回A页面的时间。
B页面离开方式:
1、当前窗口打开页面(非跳出型):监听pagehide & document.hidden=true
2、新开窗口打开页面(跳出型):监听pagehide & document.hidden=true

返回页面A方式:
1、返回后页面被动刷新:监听pageshow
2、返回后页面不刷新:监听document.hidden=false

终上所述,为了兼容设备前进后退的多种差异情况,需要融合几种监听方式,以达到覆盖多种情况的效果(经测试,在安卓版本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]) {
    // 隐藏:记录离开时间
  } else {
    // 显示:记录返回时间
  }
});

window.addEventListener('pageshow', (e) => {
  if (e.persisted || (window.performance && window.performance.navigation.type === 2)) {
    // 页面后退时操作:记录返回时间
  }
}

window.addEventListener('pagehide', (e) => {
   // 页面离开时操作:记录离开时间
}

后记

在vue中,如果已经创建了Vue示例再实行监听pageshow时间的话,是会失效的,所以,需要在未创建Vue示例前监听pageshow事件,并且可以通过window.postMessage延迟传递信息:

window.addEventListener('pageshow', (t) => {
  // persisted:查看页面是直接从服务器上载入还是从浏览器缓存中读取,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 },
    });
});

// 实现vue文件中
window.addEventListener('message', (e) => {
   if (e.origin !== window.location.origin && e.data !== 'pageshowEvent') return;
   // 后续处理
}, false);

参考文章

  1. pageshow和pagehide应用场景
  2. 移动端返回强制刷新页面pageshow事件persisted总为false解决方案

相关文章

  • 前进之前与后退之后-pageshow&pagehide

    需求背景 一个页面A需要记录在页面点击某个链接B时的时间time1,与后退返回该页面时的时间time2,得到中间的...

  • ajax与前进后退

    Ajax可以实现页面的无刷新操作但是,也会造成另外的问题,无法前进与后退,如果想既可以使用ajax做数据传输右想实...

  • 观念前进与后退

    看到这段话虽然不是特别清晰的明白,但是感觉说的很对。「这个口子一开,那还了得。」(刚才看到某热门话题的一则评论。 ...

  • 后退前进

    毕业时给自己规划的人生路线是出纳,会计,总账,成本,主管,经理,总监,亚太区总监,而今路走了一半便停了下来。 离开...

  • 前进or后退

    一场风雨过后 工地泥泞不堪 积水?短路?停电! 停摆第二天 前方的路该怎样走 没有方向 只能前行 也许我真的不适合...

  • 前进or后退

    拍摄完后,闷头走在回家的路上,突然乌云密布,狂风暴雨倾泻而下。瞬间把我浇透。 此时身上的冰冷都不及心里的冷来的更甚...

  • 练车技巧

    前进后退 调车与路的距离 前进 左侧出风口的右侧边缘 与路面右侧的黄线的左侧对齐 后退 看右侧后视镜 与路面右侧的...

  • 左眼与右眼的爱情故事

    左眼近视,右眼远视 左眼为见右,穷追不舍向前进 右眼找寻左,形影不离往后退 前进,后退 前进,后退 ······ ...

  • 儿子随想

    前进与后退[呲牙]和大家分享一下 做父母的是不是都有同感: 前进不行, 后退不沾, 无所适从, 难于登天, 为儿为...

  • 前进又后退

    走走又停停, 却不知方向, 前进一步遥, 后退一步速。 心中耐不住, 还是跨前走, 起初感新鲜, 不久心烦躁, 几...

网友评论

    本文标题:前进之前与后退之后-pageshow&pagehide

    本文链接:https://www.haomeiwen.com/subject/nkkkrktx.html