小tips-一種移動端模擬實現返回攔截的方案

移動端做爲互聯網重要入口,切圖仔前端工程師開發移動端頁面早已經是司空見慣的事了,而且其中大部分都是內嵌於客戶端(app,小程序)的 h5頁面,即 webviewhtml

有次被同事問到一個問題,他有個需求,是一個內嵌在客戶端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提供的路由守衛鉤子函數(beforeRouteEnterbeforeRouteUpdatebeforeRouteLeave)也可以達到一樣的效果,這些鉤子函數只是進一步簡化了流程,但本質都仍是同樣的,目的都是實現對路由的監聽與控制,因此你哪怕不想依賴於框架提供的能力,經過設置原生監聽函數 window.addEventListener('hashchange', callback)window.addEventListener('popstate', callback) 照樣能夠實現功能

除了經過路由控制以外,頁面元素確定也必須可以對彈層顯隱進行控制,例如點擊某個元素彈起彈層,這樣才貼合真實使用場景

一樣的,因爲彈層的顯隱其實是由路由的切換控制,因此頁面內部想要改變彈層的顯隱,也必須經過路由切換來完成:

changeVisible () {
  if (this.visible) {
    this.$router.go(-1)
  } else {
    this.$router.push('/physicsBack/footerModal')
  }
}
複製代碼

因爲這其實是利用了系統的返回能力,因此不管你在瀏覽器上仍是客戶端 appwebview內,不管是使用屏幕返回仍是物理返回鍵,均可以達到一樣的效果

實現的效果以下:

作了個 Live Demo,感興趣的能夠親自試下,代碼也已經上傳到 github

小結

本文所說的經過路由來模擬攔截返回鍵的能力,不只僅能夠應用在彈層例子上,其餘跟返回相關的操做理論上均可以發揮想象,例如返回重定向,禁止用戶退出頁面(這是什麼傻叉需求啊)

相關文章
相關標籤/搜索