Android物理返回鍵的點選事件,一般webview的預設行為是 window.history.go(-1)
,但是在實際需求場景下,簡單的頁面回退並不能滿足需求,所以需要H5頁面監聽Android物理返回鍵從而自定義處理方法。
本方案的程式碼都在 h5_android_back 倉庫中
原理
主要是運用 HTML5 History API 實現。所以,首先簡單介紹下 HTML5 History API
HTML5 History API
history 屬性
history.length
history.state
複製程式碼
history 方法
history.back()
history.forward()
history.go()
複製程式碼
HTML5 新API
history.pushState(state, title, url); 新增一條歷史記錄,不重新整理頁面
history.replaceState(state, title, url); 替換一條歷史記錄,不重新整理頁面
事件
popState事件:歷史記錄發生變化時觸發,呼叫history.pushState()
或history.replaceState()
不會觸發此事件
window.addEventListener(`popstate`, handlePopstate);
複製程式碼
hashchange事件:頁面hash
值發生改變時觸發
window.addEventListener(`hashchange`, handleHashChange);
複製程式碼
監聽Android物理返回鍵實現
// index.js
(function (pkg) {
var STATE = `_android_back`;
// 維護處理方法的棧
var _android_back_handles = [];
// 觸發一次popstate方法,則呼叫最新處理方法
var handlePopstate = function () {
var handle = _android_back_handles.pop();
handle && handle();
};
// 通過呼叫listen方法新增處理方法
var listen = function (handle) {
_android_back_handles.push(handle);
};
// 通過呼叫push方法,新增一條歷史記錄,並新增對應處理方法
var push = function (state, handle) {
if (handle) {
history.pushState(state, null, location.href);
handle && _android_back_handles.push(handle);
}
};
const init = function () {
// 通過呼叫 history.pushState() 方法新增一條歷史記錄
history.pushState(STATE, null, location.href);
// 監聽 popstate 事件,當點選Android物理返回鍵時,會觸發該事件
window.addEventListener(`popstate`, handlePopstate);
this.listen = listen;
this.push = push;
};
init.call(window[pkg] = window[pkg] || {});
})(`AndroidBack`);
複製程式碼
此實現參考了 github.com/iazrael/xba… ,在此基礎上,根據需要修改和新增了一部分程式碼
此外,封裝了一個React高階元件,方便React專案使用,程式碼如下:
import * as React from `react`;
export default (Target, handleBack) => {
return class AndroidBack extends React.Component {
_handles = []
back = () => {
window.history.go(-1);
}
componentDidMount () {
// 通過呼叫 history.pushState() 方法新增一條歷史記錄
history.pushState(`_android_back`, null, location.href);
// 監聽 popstate 事件,當點選Android物理返回鍵時,會觸發該事件
window.addEventListener(`popstate`, this.handlePopstate);
if (handleBack) {
// 新增自定義處理方法
this._handles.push(handleBack);
} else {
// 如果沒有自定義處理方法,預設呼叫 window.history.go(-1);
this._handles.push(this.back);
}
}
componentWillUnmount () {
window.removeEventListener(`popstate`, this.handlePopstate);
}
// 觸發一次popstate方法,則呼叫最新處理方法
handlePopstate = () => {
const handle = this._handles.pop();
handle && handle();
}
// 通過呼叫push方法,新增一條歷史記錄,並新增對應處理方法
push = (state, handle) => {
if (handle) {
history.pushState(state, null, location.href);
this._handles.push(handle);
}
}
render () {
return (
<Target {...this.props} _android_back_push={this.push}/>
);
}
};
};
複製程式碼
實現原理基本在註釋中註明,在這就不詳細敘述了,所有程式碼在 h5_android_back 倉庫中
使用
兩種方式:
1、將物件掛在window上,支援任意頁面接入,使用如下:
index.js
// 監聽Android物理返回鍵,自定義處理方法
window.AndroidBack.listen(() => {
console.log(`back`);
});
// 新增Android物理返回鍵監聽事件,使用場景,比如:頁面內彈出浮層,點選Android物理返回鍵,不是回退頁面,而是關閉浮層
window.AndroidBack.push(`close_modal`, () => {
// 關閉彈窗
console.log(`close_modal`);
});
複製程式碼
2、封裝了React高階元件,支援React專案接入,使用如下:
index_react.js
import * as React from `react`;
import AndroidBack from `h5_android_back/index_react.js`;
class App extends React.Component {
// ...
openModal = () => {
// 新增Android物理返回鍵監聽事件,使用場景,比如:頁面內彈出浮層,點選Android物理返回鍵,不是回退頁面,而是關閉浮層
this.props._android_back_push(`close_modal`, () => {
// 關閉彈窗
console.log(`close_modal`);
});
}
}
// 監聽Android物理返回鍵,自定義處理方法
export default AndroidBack(App, () => {
console.log(`back`);
})
複製程式碼
寫在最後
注:此方案使用於所有瀏覽器及預設行為是頁面回退的webview
此方案在我平時工作中使用正常,希望能對有需要的小夥伴有幫助~~~
喜歡我的文章小夥伴可以去 我的個人部落格 點star ⭐️