需求
最近开发 React 项目中遇到了这么一个需求
比如项目中有页面 A、页面 B、页面 C、页面 D,前端使用 react-router 进行正常路由跳转,路由为:A -> B -> C -> D。当页面到 D 的时候点击返回(无论是 HeaderBar 还是实体返回按钮)要返回到页面 A,且无论什么情况下在页面 A 点击返回都要退出 H5 页面返回 Native 界面。
关键点
由于 HeaderBar 的返回按钮行为由 native 端通过 JSBridge 提供了监听事件,所以很简单。
window.back = () => {
const pathname = window.location.pathname;
if (pathname.indexOf('/A') > -1) {
jsbridge.pop(); // jsbridge 的退出 H5 事件
} else if (pathname.indexOf('/D') > -1) {
this.props.history.push({
pathname: 'A'
});
} else {
this.props.history.goBack();
}
}
但是 Android 的物理返回按钮走得是正常的 history 返回上一页流程。
解决 Android 物理返回键
查了不少监听 Android 返回键行为监听的方法,发现都是监听 popstate
方法来做的。
页面A
componentDidMount() {
window.addEventListener('popstate', this.goBack);
window.history.pushState(null, '', '');
}
componentWillUnmount() {
window.removeEventListener('popstate', this.goBack);
}
goBack = () => {
jsbridge.pop(); // jsbridge 的退出 H5 事件
}
页面D
componentDidMount() {
window.addEventListener('popstate', this.goIndex);
window.history.pushState(null, '', '');
}
componentWillUnmount() {
window.removeEventListener('popstate', this.goIndex);
}
// 去页面 A
goIndex = () => {
this.props.history.push({
pathname: 'A'
});
};
简单解释下,当前页面是 A,点击返回则直接调用 native 的退出 H5 接口行为;当页面在 D,点击返回则跳转到页面 A。这样就避免了 history 中的复杂路由处理了,简单粗暴。
另外注意到 window.history.pushState(null, '', '');
这段代码,为什么要推一个空的页面呢?
因为 popstate
事件的触发机制是:当 A 监听了 popstate 事件,那么从 B 返回到 A 时会触发 A 的 popstate
事件。所以监听当前页的方法就是往 window.history 中再推一个空值。这样就能在返回事件中触发 popstate
事件。
页面加载时Chrome和Safari通常会触发(emit )popstate事件