webview裏的返回事件處理

最近在項目中遇到一個webview中的返回問題,以爲比較有價值,在這裏記錄下。javascript

問題所在

需求是在安卓客戶端APP中用webview打開vue的單頁應用,在vue應用中,路由本身管理,每次點擊導航欄的返回按鈕,都返回上級路由頁面,當回到最初webview打開所在的頁面時,再點擊返回按鈕,就調用客戶端提供的 clientApi.goBack() 方法,會銷燬掉這個webview,回到客戶端app所在的頁面。vue

在這個 vue 應用中,有 A、B、C、D、E,五個頁面,彼此之間均可以相互跳轉,每一個頁面均可能是客戶端APP打開webview時所處的第一個頁面。那麼問題來了,假設某一次打開 webview 時,進入的是 C 頁面,在應用內各類跳轉,而後一級級地返回,返回到了 C 頁面,如何判斷該調用 clientApi.goBack() 了呢?java

尋找解決方案

我嘗試在 C 頁面調用 router.back(), 沒有任何反應,固然,這是JS的代碼,銷燬webview已經超出了它的權限。在 routerouter 中都沒有找到任何能判斷當前頁面就是打開 webview 時所在的頁面的線索,又嘗試在 window.history 中找找線索。web

window.history 有三個屬性:app

  • length
  • scrollRestoration
  • state

前面兩個用不了,因而嘗試下state.ui

發現每次路由變化以後,window.history.state 都是不一樣的值, 例如:this

{
    key: "icgo4i",
    state: undefined
}
複製代碼

初始頁面的 window.history.state 多是 null, 也多是一個如上的對象。嘗試進行幾回路由跳轉,而後再返回,發現同一個頁面,在不一樣的路由時機,其 window.history.state 的值是不一樣的,好比,當前在 A 頁面,其 window.history.state 值爲:spa

{
    key: "icgo4i",
    state: undefined
}
複製代碼

跳轉到 B頁面,由B頁面跳轉至 C 頁面,再由 C 頁面跳轉至 A 頁面,那麼此時 A 頁面的 window.history.state 的值爲:code

{
    key: "0yfpsb",
    state: undefined
}
複製代碼

與前一個 A 頁面的值是不一樣的。router

而後再由A頁面一路調用 router.back() 或者window.history.back(),返回到最初的 A 頁面,此時 window.history.state 值又變成了:

{
    key: "icgo4i",
    state: undefined
}
複製代碼

能夠看到,與原來的值同樣。

解決方案

問題終於有了解決方案,根據 window.history.state 的記憶功能,即可以判斷當前頁面是不是打開 webview 時所處的頁面。步驟以下:

  • h5 APP加載後,記錄下當前頁面的 window.history.state
  • 每次調用點擊左上角返回按鈕時,判斷當前頁面的 window.history.state 與所記錄的值是否同樣
  • 若同樣,則調用 clientApi.goBack(), 不然調用 router.back()

參考代碼

vue版參考代碼以下:

// store
state: {
	initialHistoryStateStr: '',
}

mutations: {
	setHistoryInitialStateStr(state: State, initialHistoryStateStr: string) {
	    state.initialHistoryStateStr = initialHistoryStateStr;
	},
}

// common.js
if (store.state.initialHistoryStateStr === JSON.stringify(window.history.state)) {
  clientApi.goBack();
} else {
  router.back();
}

// App
created() {
	this.$store.commit('setHistoryInitialStateStr', JSON.stringify(window.history.state));
	window.handleClientGoBack = () => {
      common.goBack();
    };
    clientApi.on('back', handleClientGoBack'); // 監聽客戶端物理返回按鍵點擊
}
複製代碼

原生js版參考代碼以下:

window.addEventListener('load', function() {
	window.__initialHistoryStateStr = JSON.stringify(window.history.state);
}, false);

const common = {
	back() {
		const nowHistoryStateStr = JSON.stringify(window.history.state);
		if (nowHistoryStateStr === window.__initialHistoryStateStr) {
			clientApi.goBack();
		} else {
			window.history.back();
		}
	}
}
window.handleClientGoBack = () => {
  common.goBack();
};
clientApi.on('goBack', 'handleClientGoBack');  // 監聽客戶端物理返回按鍵點擊
複製代碼
相關文章
相關標籤/搜索