移动端做为互联网重要入口,切图仔前端工程师开发移动端页面早已经是司空见惯的事了,而且其中大部分都是内嵌于客户端(app
,小程序)的 h5
页面,即 webview
html
有次被同事问到一个问题,他有个需求,是一个内嵌在客户端app
内的页面,有个功能点是拦截客户端的返回操做,实现页面内弹层的显示与隐藏,拦截点包括 app
页面上自带的返回按钮以及安卓机的物理按钮,相似于下面这种:前端
点击购物车,则购物车元素从页面底部弹起显示,点击遮罩层,则弹层关闭隐藏,这是很正常的操做,而除此以外,还须要实现的一个功能是,点击屏幕返回键或者安卓机的物理返回键,也可以关闭弹层,而且保证页面不发生跳转vue
我听了微微一笑,问他,哪一个傻叉 客户端那边有提供拦截返回的 PM
提的需求?,h5
怎么拦截 app
甚至是物理按钮的操做?你当时没有怼他吗?sdk
接口吗?同事回答 sdk
没有提供这个能力,他以为很差实现,但 PM
坚持要作这个功能git
因而我抱着反正不是个人需求,我天马行空章口就来瞎提建议也不要紧助人为乐的态度思考了一会,谁知还真让我想到了一个方案(我不肯定之前是否是在什么地方看到过,总之就是想到了),回来验证了一下,确实是可行的github
关键点在于,利用返回操做会触发路由改变的特性来模拟达到拦截的效果,并非真的监听或者拦截到了屏幕返回键或者物理返回键的点击web
假设须要进行模拟拦截返回操做的主页面路由为 /physicsBack
,其下有个子路由 /physicsBack/footerModal
,当路由为 /physicsBack
时就只显示页面,当路由为 /physicsBack/footerModal
时,就在 /physicsBack
上弹起弹层vue-router
这里的 /physicsBack/footerModal
提及来是子路由,但实际上咱们只是想利用其做为路由的一个能力——即拦截返回操做,因此实际上并不真的须要为这个路由配置一个页面,你固然也能够这么作,最后也能实现效果,但未免麻烦了些小程序
这里我将 /physicsBack
和 /physicsBack/footerModal
所有指向同一个页面,即主页面,而后经过对路由的监听,来控制弹层的显隐浏览器
路由配置以下:前端工程师
const router = new VueRouter({
routes: [{
path: '/physicsBack/(footerModal)?',
component: physicsBack
}]
})
复制代码
/physicsBack/(footerModal)?
同时匹配 /physicsBack
和 /physicsBack/footerModal
,因此不管路由是 /physicsBack
仍是 /physicsBack/footerModal
,都将指向 physicsBack
这个页面,达到即便路由在这两个中来回切换,但页面也毫无变化的目的
虽然在路由 /physicsBack
和 /physicsBack/footerModal
中切换不会引发页面的切换,自始至终都停留在 physicsBack
组件上,但却能够在 physicsBack
组件中对路由进行监听,进而根据监听到的路由变化来控制弹层的显隐:
watch: {
$route (to, from) {
this.manageFooterModal(to.path, from.path)
}
}
// ...
manageFooterModal (toPath, fromPath) {
if (toPath === '/physicsBack/footerModal') {
this.visible = true
} else if (fromPath === '/physicsBack/footerModal') {
this.visible = false
}
}
复制代码
当 toPath
是 /physicsBack/footerModal
,表示将切换到这个路由,前面已经规定了,当路由切换到这个位置时,显示弹层;
当 fromPath
是 /physicsBack/footerModal
,表示从有弹层的页面回退或者跳走,则关闭弹层
这里你不用 watch
也是能够的,用 vue-router
提供的路由守卫钩子函数(beforeRouteEnter
、beforeRouteUpdate
、beforeRouteLeave
)也可以达到一样的效果,这些钩子函数只是进一步简化了流程,但本质都仍是同样的,目的都是实现对路由的监听与控制,因此你哪怕不想依赖于框架提供的能力,经过设置原生监听函数 window.addEventListener('hashchange', callback)
或 window.addEventListener('popstate', callback)
照样能够实现功能
除了经过路由控制以外,页面元素确定也必须可以对弹层显隐进行控制,例如点击某个元素弹起弹层,这样才贴合真实使用场景
一样的,因为弹层的显隐其实是由路由的切换控制,因此页面内部想要改变弹层的显隐,也必须经过路由切换来完成:
changeVisible () {
if (this.visible) {
this.$router.go(-1)
} else {
this.$router.push('/physicsBack/footerModal')
}
}
复制代码
因为这其实是利用了系统的返回能力,因此不管你在浏览器上仍是客户端 app
的 webview
内,不管是使用屏幕返回仍是物理返回键,均可以达到一样的效果
实现的效果以下:
作了个 Live Demo,感兴趣的能够亲自试下,代码也已经上传到 github
本文所说的经过路由来模拟拦截返回键的能力,不只仅能够应用在弹层例子上,其余跟返回相关的操做理论上均可以发挥想象,例如返回重定向,禁止用户退出页面(这是什么傻叉需求啊)等