一、离开路由弹出弹窗
最近做一个h5的需求,要求在用户页面返回时如果操作了就弹出一个弹窗,来提示用户是否保存此页面所操作的内容。
之前做过vue的路由守卫,但是react的还是第一次做,就记录一下。
首先需要引入withRouter,来包裹一下需要弹窗的页面,此时在componentDidMount中才能获取到 this.props.route,
因为我们的项目需要弹窗的页面是又通过HOC高阶组件进行了一次嵌套的,所以用withRouter来包装弹窗页面,而componentDidMount中的内容是写在HOC组件中的,这样才能达到效果。
这样就可以在routerWillLeave函数中写一些逻辑来判断是否弹出,nextLocation是接下来要跳转的路由,如果要阻止就return false,否则就return true;
import { withRouter } from 'react-router';
componentDidMount() {
this.props.router.setRouteLeaveHook(this.props.route,this.routerWillLeave.bind(this));
}
routerWillLeave(nextLocation) {
//nextLocation 接下来要跳转的路由
//isChange 页面是否有更改
return isChange ? false : true;
}
export default withRouter(Component);
二、h5和app的交互
1.其他第三方
因为我们项目不仅仅是内嵌在微信公众号、企业微信、钉钉里面的,还涉及到在原生app中app的功能调用h5页面,所以还涉及到和app的交互。
如果内嵌在比如微信公众号中,如果直接点左上角的X,就等于直接把这个页面关闭了,相当于浏览器的关闭页面,是无法监听到的,只有在点下面的<左箭头返回或者手势右滑,这样才被认为是页面的路由回退事件,这样才能监听到。
2.自己的app
但是我们的app中第一种情况是直接点击就进入到这个页面的,左上角的返回按钮是app中的,点返回就直接关闭页面了,监听不到路由回退,所以就不会生效。
还有一种情况是app进入到了h5页面,在h5页面点击又跳转了另一个h5页面。这时上方会有一个返回按钮和X按钮,点击X就是直接关闭页面了,点击返回就相当于h5页面直接的路由跳转,所以又能监听到路由回退事件,所以要考虑到这种。
如何解决这个问题呢,经过和app人员讨论之后,方案如下:
在app进入h5页面的时候,h5给app传递一个标识type,1表示需要在离开时进行二次确认,0表示取消标识。这样在h5的componentDidMount中传递给app一个标识,app接受到之后,就会控制app中的左上角的返回按钮,点击的话不会返回,而是调用h5的一个方法,传递参数,交给h5来处理,然后h5经过判断页面有没有更改之后,决定是否弹弹窗,在用户操作完之后,调用app提供的关闭页面的方法,关闭此页面,在componentWiilUnmount中再取消这个标识,防止出错。
这样以上的两种情况就都得到了解决,h5再跳转h5的情况,虽然点击的还是app的按钮,但由于我们再跳转h5的页面不传标识,所以点app的返回相当于路由回退,是没问题的。
1.向app传递标识的代码
export const appSendNeedConfirm = (type) => {
const userAgentInfo = navigator.userAgent.match(/MyApp/i);
const appVersion = getCurrVersion();
if(userAgentInfo && compareVersion(appVersion,'2.2.3')){
if(userAgentInfo.match(/Mac OS X/i)){
try{
window.webkit.messageHandlers.setNeedConfirm.postMessage(type);
} catch (e) {
window.setClosePageNeedConfirm(type);
}
}else {
//无参数的话不用传null
window.android.setNeedConfirm(type);
}
}
}
// 获取当前版本号
function getCurrVersion() {
const userAgentInfo = navigator.userAgent;
let singApp = userAgentInfo.indexOf('MyApp/');
if(singApp !== -1) {
let start = +singApp + 5;
let end = userAgentInfo.indexOf(')', start);
return userAgentInfo.substring(start, end);
}
return '';
}
2. 至于app如何调用h5的方法,我写在了componentDidMount中,在window上暴露这个方法,然后监听,如果app点击了返回就会调用此方法,并传一个参数type,来标识返回的类型,那么在回调中就能接收到,然后再进行相关判断逻辑的处理就可以了。
//h5向app提供接口wannaClosePage参数 0/1,app调用之后,需要判断是否需要弹窗
window.wannaClosePage = function(type){
//这里的逻辑和routerWillLeave中判断是否更改的逻辑是一样的
}
3.在保存接口执行完之后,h5调用app提供的方法,来关闭页面。