移動端做爲互聯網重要入口,切圖仔前端工程師開發移動端頁面早已經是司空見慣的事了,而且其中大部分都是內嵌於客戶端(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
本文所說的經過路由來模擬攔截返回鍵的能力,不只僅能夠應用在彈層例子上,其餘跟返回相關的操做理論上均可以發揮想象,例如返回重定向,禁止用戶退出頁面(這是什麼傻叉需求啊)等