移动端react/H5开发通过JS捕捉安卓物理返回键的实践
业务需求及要求一共5个页面,页面内有导航栏和返回,其中两个页面的返回有特殊要求,而且物理返回键点击动作要和导航中的返回完全一致。首页——项目一打开在首页,点击某个元素跳转到列表页列表页——可以点击新增跳到表单编辑页,点击草稿可以跳到草稿箱,点击每个图可以跳到详情页;点返回回到首页。详情页——点击编辑可以跳到表单编辑页;表单编辑页——点击保存跳到草稿箱,点击提交跳到列表页;草稿箱——点击每个图片进入
·
业务需求及要求
一共5个页面,页面内有导航栏和返回,其中两个页面的返回有特殊要求,而且物理返回键点击动作要和导航中的返回完全一致。
- 首页——项目一打开在首页,点击某个元素跳转到列表页
- 列表页——可以点击新增跳到表单编辑页,点击草稿可以跳到草稿箱,点击每个图可以跳到详情页;点返回回到首页。
- 详情页——点击编辑可以跳到表单编辑页;
- 表单编辑页——点击保存跳到草稿箱,点击提交跳到列表页;
- 草稿箱——点击每个图片进入表单编辑页;点返回回到列表页。
解决过程
网查了一下,花了大半天时间尝试了以下方法
1,监听popstate事件
可以通过监听popstate事件来感知也变化,但不能保证一定是点了返回键触发的,也就是正常的路由跳转全被监听了。这个类型的版本有好几个,都存在此问题。
window.addEventListener("popstate", function(e) {
window.location.replace(url)//点击返回键时,需要返回的页面
}, false);
2,封装的XBack来阻止安卓返回键
找到了XBack代码片段,发现放在全局初始化就会把任何情况下的返回键屏蔽掉,如果放在导航栏组件里就可以成功捕捉到并阻止物理返回键,但这种情况下跳转一下容易触发好几十次的路由跳转,且每次不尽相同,最终的路径也不一定是想要的,也懒得用防抖节流再试了。
let XBack = {};
const {location,history} = window;
(function(XBack) {
XBack.STATE = 'x - back';
XBack.element ={};
XBack.onPopState = function(event) {
event.state === XBack.STATE && XBack.fire();
XBack.record(XBack.STATE); //初始化事件时,push一下
};
XBack.record = function(state) {
history.pushState(state, null, location.href);
};
XBack.fire = function() {
var event = document.createEvent('Events');
event.initEvent(XBack.STATE, false, false);
XBack.element.dispatchEvent(event);
};
XBack.listen = function(listener) {
XBack.element.addEventListener(XBack.STATE, listener, false);
};
XBack.init = function() {
XBack.element = document.createElement('span');
window.addEventListener('popstate', XBack.onPopState);
XBack.record(XBack.STATE);
};
})(XBack); // 引入这段js文件
XBack.init();
XBack.listen(function() {
console.log('----------物理键返回', backUrl,)
if(backUrl){
// window.history.pushState("","",'/#'+backUrl);
// window.history.pushState("","",'http://'+window.location.host+'/#'+backUrl);
// window.location.href='http://'+window.location.host+'/#'+backUrl;
window.location.replace('/#'+backUrl)
}else{
// window.history.back()
}
});
3,其他方法
- 通过在跳转的目标页面进行检测拦截来实现。经分析,只需在form页面判断,如果来自草稿箱,则跳到列表页;如果来自列表页则跳到App。但问题是,这两个页面需要返回到不同的页面,但无法区分来源。
- 打印history对象,企图从中找到些路径先后关系的信息,无果,其中action的值也仅能判断出是跳过来的还是退回来的,对草稿箱和列表页都能退回的form页,仍然无法区分。
- 曾尝试过一个方法:为了区分物理返回键和导航栏返回键,在导航栏返回时将一个外部变量标记,再用setTimeout在200ms后清除标记。在此期间通过监听popstate和判断标记来区分是否物理按键。但这样需要把所有跳转都标记出来。结论
终极大法
- 每个页面加载时,在constructor中将页面标记pageMark写入sessionStorage中:列表页1,详情页2,编辑页3,草稿箱4.
- 进入相关页面时先判断history的行为是否后退(props.history.action==='POP'),如果是说明按了返回键(无需判断是物理返回键还是页面内的回退),再根据以下情况判断
- 在编辑页
- 如果是4就说明来自草稿箱,就执行跳转到列表页;
- 如果是1就说明来自列表页,执行跳转到首页。
- 在草稿箱
- 如果是1就说明来自列表页,执行跳转到首页。
- 在编辑页
- 例如form页面的constructor
constructor(props) {
super(props);
if(props.history.action==='POP'){ // 说明后退了
const pageMark = sessionStorage.getItem('pageMark');
if(pageMark==='4'){ // 从草稿箱要回来
this.props.history.push('/list')
}
if(pageMark==='1'){ // 从列表要回来
this.props.history.push('/')
}
}
sessionStorage.setItem('pageMark','3');
……
}
更多推荐
已为社区贡献2条内容
所有评论(0)