popstate与pushState和物理返回

1,137 阅读1分钟

问题描述

foo页面有个返回挽留的弹窗,点击自定义的返回箭头是ok的,但是如果使用android的物理返回键就GG了。

解决思路

window.addEventListener('popstate', cb)来接管浏览器的返回按钮操作,也就是adnroid上面的物理返回操作。

遇到的问题

  • 直接在foo页面注册了popstate后,发现点击浏览器的返回按钮并没有执行popstate的cb
    • 解决方案就是注册popstate之后,直接history.pushState,这样在点击浏览器的返回按钮的时候才能出发popstate事件。

案例分析

  • foo页面注册popstate,执行alert(2), 然后pushState到bar页面,此时访问baidu.com。点击返回回到bar页面,不会触发alert(2),在bar页面继续点击返回回到foo页面,依然不会触发alert(2),在foo页面继续点击返回按钮,回到上个页面,还是没有alert(2)。
    • 为何baidu回到bar没有alert(2)?
      • 因为baidu并没有注册popstate
    • 为何bar回到foo没有alert(2)?
      • 因为bar页面也没有注册popstate
    • 为何foo返回没有alert(2)?
      • 因为foo页面没有执行pushState

总结

通过遇到的问题以及案例分析,我们得知要想在foo页面触发popstate需要满足两个条件,1:foo页面注册了popstate 2:foo页面执行了pushState

// physicalBack.js
const physicalBack = {
  register(cb) {
    this.destroy();
    this.cb = () => {
      cb && cb();
      this.destroy();
    }
    window.addEventListener('popstate', this.cb)
    window.history.replaceState({ page: 'physicalBack' }, 'physicalBack');
  },
  destroy() {
    window.removeEventListener('popstate', this.cb);
  }
};

export default physicalBack;



// 使用
import physicalBack from './physicalBack'
useEffect(()=>{
	physicalBack.register(()=>{console.log('physicalBack')});
    return ()=>{
    	phyicalBack.destroy();
    }
},[])