做过移动端的同学都知道,手机的物理返回键不好控制,这里梳理了一下关于物理返回键针对不同场景的处理。
一、概述
物理返回处理分为两类,一类是当前APP提供我们监听物理键的返回事件,一类没有;针对第一种,就无需考虑了,这里我们主要讲解第二种。
HTML5提供我们两个事件可以监听物理返回:popState、hashChange,这里主要用popState。
首先,我们来了解一下popSate,在MDN文档是这么说的:
当活动历史记录条目更改时,将触发popstate事件。如果被激活的历史记录条目是通过对history.pushState()的调用创建的,或者受到对history.replaceState()的调用的影响,popstate事件的state属性包含历史条目的状态对象的副本。需要注意的是调用
history.pushState()
或history.replaceState()
不会触发popstate
事件。只有在做出浏览器动作时,才会触发该事件,如用户点击浏览器的回退按钮(或者在Javascript代码中调用history.back()
或者history.forward()
方法)不同的浏览器在加载页面时处理
popstate
事件的形式存在差异。页面加载时Chrome和Safari通常会触发(emit )popstate
事件,但Firefox则不会。
以上就是popSate的触发时机。
二、物理返回处理
目前物理返回我只碰到过4种情况,后续有新增的再更新文档。由于我们的项目是单页应用,这里也以单页应用为例。
1、当前路由返回需要跳转到别的页面
针对这种情况,有明确的下一个页面的路由,这时只需要用router.push/replace直接跳转即可
2、返回上一页
由于我们的物理返回本来就是会返回上一页的,所以针对这种情况其实也什么都不用处理
3、第一次返回需要弹窗提示用户,当前不返回,第二次返回时才真正返回
由于物理返回始终要返回一次的,而这里我们不让放回,那何不直接将当前的链接再放入历史记录呢,这样就算返回了,我们还在当前页面,这里我们调用:history.pushState(null, null, currentUrl)
,由于pushState不用触发popState事件,所以这里无需担心popState还会触发一次。
需要注意的是,在popState的回调函数中调用window.location.href已经是返回后的链接了,如果要获取返回之前的,建议调用 router.currentRoute
获取,该值的改变在popState事件之后;这里我们的currentUrl = '#' + router.currentRoute.fullPath
4、不同项目之间相互跳转时,当回到某个项目首页时,由于进入该项目后来回跳转了,所以此时在首页想要返回到进入该项目之前的页面
由于来回跳转,所以直接返回肯定是返回不回去的,这个时候需要记录一下进入该项目的时候的history.length,始终保持history.length最小,当在项目首页要返回进入该项目的页面是,用当前的history.length与之前记录的历史长度recordedHistoryLength做比较,如果history.length > recordedHistoryLength
,则调用history.go(recordedHistoryLength - history.length -1)
返回
三、注意
最后,还有一点需要注意的,因为我们的单页面应用除了物理返回还有正常路由的跳转,由于vue-router的mode默认值为hash,当执行路由跳转时比如push、replace最终会调用vue-router文件中的pushHash
与replaceHash
,该方法有两种执行方式:
1、只有在支持pushState
的情况下才会调用history的pushState/replaceState
2、否则使用window.location.hash
/window.location.replace
进行跳转
针对这两种执行方式,这里分两种情况:
1、提前打包vue-router成lib
由于打包的时候是属于node环境,没有window,window并没有history属性,更没有pushState
,所以会走第二种执行方式,这种情况下是会触发popState事件,此时我们可以在router的beforeEach事件回调中执行时存储一个变量,表示当前为普通路由跳转,因为普通路由跳转的执行机制会先触发router的beforeEach,再执行history的方法跳转,想要深入了解的同学可以去看一下vue-router的源码,所以这里,需要在popState事件中加上判断,如果刚刚执行过beforeEach了,则这次url改变不执行popState回调中调用的方法2、如果没有提取打包成lib,直接引用
这种情况会执行第一种方式,由于执行pushState/replaceState是不触发popState事件的,此时无需添加多余的逻辑
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。