JS如何判断用户是否点击浏览器“退回”按钮返回上一个界面?

广告位招租
扫码页面底部二维码联系

通过window的popstate事件可【版权所有,侵权必究】未经授权,禁止复制转载。以监听history的变化,但是,“po【原创不易,请尊重版权】【未经授权禁止转载】pstate会在浏览器前进后退操作、hi未经授权,禁止复制转载。【本文受版权保护】story.go/back/forwar【未经授权禁止转载】著作权归作者所有,禁止商业用途转载。d调用、hashchange的时候触发”【本文受版权保护】本文作者:唐霜,转载请注明出处。,它是一个复合事件,你根本判断不了到底是本文版权归作者所有,未经授权不得转载。【本文受版权保护】哪种情况引起的popstate。更难理解【本文首发于唐霜的博客】原创内容,盗版必究。的是,我不知道为什么要把forward也【原创不易,请尊重版权】【关注微信公众号:wwwtangshuangnet】设计为popstate,pop这个词的意【版权所有】唐霜 www.tangshuang.net【本文受版权保护】思不就是从stack顶把最上面的一个从栈【本文受版权保护】【版权所有】唐霜 www.tangshuang.net中移除么?forward明显是push的【版权所有】唐霜 www.tangshuang.net未经授权,禁止复制转载。行为,怎么也放到popstate里面。这【访问 www.tangshuang.net 获取更多精彩内容】未经授权,禁止复制转载。个事件明显是有设计缺陷的。回到题目,我们【原创不易,请尊重版权】【未经授权禁止转载】怎么去判断用户是点击了“退回”按钮?

【本文首发于唐霜的博客】原创内容,盗版必究。【原创不易,请尊重版权】

我们要用到一些取巧的办法。具体我总结为3【转载请注明来源】【原创内容,转载请注明出处】步:

【本文受版权保护】转载请注明出处:www.tangshua【未经授权禁止转载】【本文首发于唐霜的博客】ng.net【转载请注明来源】未经授权,禁止复制转载。
  • 充实history stack,以提供更原创内容,盗版必究。【版权所有】唐霜 www.tangshuang.net多信息让我们可以在用户刷新浏览器的情况下本文作者:唐霜,转载请注明出处。【访问 www.tangshuang.net 获取更多精彩内容】,仍然获得上下页信息关联
  • 【原创内容,转载请注明出处】【版权所有】唐霜 www.tangshu著作权归作者所有,禁止商业用途转载。【作者:唐霜】ang.net
  • 为history创建一个私有的记录值,用【原创不易,请尊重版权】未经授权,禁止复制转载。以区分history当前的state和上【版权所有,侵权必究】本文版权归作者所有,未经授权不得转载。一个state(我们在事件回调中只能拿到【原创内容,转载请注明出处】【本文受版权保护】当前state)
  • 【转载请注明来源】【原创不易,请尊重版权】【关注微信公众号:wwwtangshua【关注微信公众号:wwwtangshuangnet】【作者:唐霜】ngnet】【原创内容,转载请注明出处】
  • 通过第一步和第二步铺垫的内容,在回调函数未经授权,禁止复制转载。【本文首发于唐霜的博客】中进行判断,从而判断是否是用户点击了“退【版权所有,侵权必究】本文作者:唐霜,转载请注明出处。回”按钮
  • 【未经授权禁止转载】【作者:唐霜】【关注微信公众号:wwwtangshua未经授权,禁止复制转载。【原创内容,转载请注明出处】ngnet】【未经授权禁止转载】

接下来我们进行实施。在此之前,我们需要了【转载请注明来源】【关注微信公众号:wwwtangshuangnet】解一些简单的知识。history是浏览器【访问 www.tangshuang.net 获取更多精彩内容】原创内容,盗版必究。用户记录用户浏览器历史的全局对象,既然是【转载请注明来源】【版权所有】唐霜 www.tangshuang.net“浏览历史”,那么就是一组单一数据的列表转载请注明出处:www.tangshuang.net【转载请注明来源】(有顺序),这个所谓单一数据,就是其内部【本文受版权保护】本文版权归作者所有,未经授权不得转载。的state概念,一个state表示用户【版权所有,侵权必究】【关注微信公众号:wwwtangshuangnet】在浏览一个界面(对应一个url)时留下的未经授权,禁止复制转载。本文作者:唐霜,转载请注明出处。痕迹,不过,这个state必须由开发者定【版权所有】唐霜 www.tangshuang.net【原创内容,转载请注明出处】义,如果开发者不定义,那么state就是未经授权,禁止复制转载。【作者:唐霜】null,而且为null的时候,就没哟意未经授权,禁止复制转载。【关注微信公众号:wwwtangshuangnet】义。注意,浏览器不会主动帮你记录当前的u【作者:唐霜】本文作者:唐霜,转载请注明出处。rl,虽然它自己记录在了浏览器内部,你可转载请注明出处:www.tangshuang.net【访问 www.tangshuang.net 获取更多精彩内容】以通过浏览器的“浏览历史”功能查看,但是著作权归作者所有,禁止商业用途转载。【作者:唐霜】,你无法在代码层面直接读取这些历史记录,未经授权,禁止复制转载。【本文受版权保护】你只能读取history当前的state【转载请注明来源】著作权归作者所有,禁止商业用途转载。,即通过 window.history.state 来读取,当然,你也可以通过 window.location 来读取当前的url信息。“只能读取当前【原创不易,请尊重版权】原创内容,盗版必究。的”,也就意味着这是一种栈结构的数据管理著作权归作者所有,禁止商业用途转载。【版权所有,侵权必究】,而且,这个栈在用户刷新当前浏览器tab本文作者:唐霜,转载请注明出处。未经授权,禁止复制转载。时,仍然是维持的。

本文版权归作者所有,未经授权不得转载。【作者:唐霜】原创内容,盗版必究。

基于这一特性,我们可以自己在state栈【转载请注明来源】原创内容,盗版必究。中,构建一个链表结构,从而可以读取整个栈著作权归作者所有,禁止商业用途转载。【本文首发于唐霜的博客】内的state链。具体怎么做呢?

【作者:唐霜】【版权所有】唐霜 www.tangshu著作权归作者所有,禁止商业用途转载。【转载请注明来源】ang.net【访问 www.tangshuang.n【关注微信公众号:wwwtangshuangnet】本文版权归作者所有,未经授权不得转载。et 获取更多精彩内容】转载请注明出处:www.tangshua【作者:唐霜】【原创内容,转载请注明出处】ng.net

我们知道history有pushStat未经授权,禁止复制转载。【原创内容,转载请注明出处】e和replaceState两个接口,对【访问 www.tangshuang.net 获取更多精彩内容】转载请注明出处:www.tangshuang.net于SPA应用而言,整个应用中只会使用pu【原创不易,请尊重版权】【本文受版权保护】shState和replaceState【原创不易,请尊重版权】【作者:唐霜】两个接口进行url的跳转(还有一种是在a【原创不易,请尊重版权】【原创不易,请尊重版权】标签href中使用#触发,例如 <a href="#/base/xxx"> 这种也可以做到无刷新的界面跳转,但是由著作权归作者所有,禁止商业用途转载。著作权归作者所有,禁止商业用途转载。于它走另外一个体系,也就是hashcha【本文受版权保护】著作权归作者所有,禁止商业用途转载。nge的体系,是比较老的技术,现在大部分本文版权归作者所有,未经授权不得转载。【原创内容,转载请注明出处】框架都是基于state的体系来做,因此,【本文受版权保护】【版权所有,侵权必究】我们本文不考虑hashchange这种方【关注微信公众号:wwwtangshuangnet】【作者:唐霜】案),因此,我们可以对这两个接口进行改造本文作者:唐霜,转载请注明出处。【版权所有,侵权必究】,从而在跳转时,对state进行信息充实著作权归作者所有,禁止商业用途转载。著作权归作者所有,禁止商业用途转载。

原创内容,盗版必究。转载请注明出处:www.tangshua【作者:唐霜】原创内容,盗版必究。ng.net
const originalPushState = history.pushState.bind(history);

// 要求在调用pushState时state必须是一个对象
history.pushState = function(state, title, url) {
  const { state: currentState } = history; // 获取未跳转之前的state,也就是当前的state
  const nextState = state || {};
  nextState.prevState = currentState;
  originalPushState(nextState);
};

通过这一改造,我们重写了history.【版权所有,侵权必究】本文版权归作者所有,未经授权不得转载。pushState,这样我们就让每一个被【转载请注明来源】【原创不易,请尊重版权】push到state栈中的state拥有著作权归作者所有,禁止商业用途转载。原创内容,盗版必究。了prevState属性,通过该属性就可【版权所有】唐霜 www.tangshuang.net【访问 www.tangshuang.net 获取更多精彩内容】以形成一条反向链表,用以追踪state之【未经授权禁止转载】未经授权,禁止复制转载。间的关系。

【本文首发于唐霜的博客】【版权所有,侵权必究】【原创不易,请尊重版权】

接下来,我们创建一个私有的变量,用来记录【本文首发于唐霜的博客】本文作者:唐霜,转载请注明出处。history.state发生变化前的s著作权归作者所有,禁止商业用途转载。本文作者:唐霜,转载请注明出处。tate.

著作权归作者所有,禁止商业用途转载。【原创内容,转载请注明出处】转载请注明出处:www.tangshua原创内容,盗版必究。著作权归作者所有,禁止商业用途转载。ng.net【作者:唐霜】
let latestState = history.state;

window.addEventListener('popstate', () => {
  const prevState = latestState;
  const { state } = history;
  latestState = state;
  ....
})

在每一次popstate被触发时,我们去本文版权归作者所有,未经授权不得转载。【关注微信公众号:wwwtangshuangnet】修改latestState,这样,我们就【关注微信公众号:wwwtangshuangnet】【作者:唐霜】可以记录在state发生变化前的stat【版权所有,侵权必究】【版权所有】唐霜 www.tangshuang.nete是哪一个。

著作权归作者所有,禁止商业用途转载。【访问 www.tangshuang.n【关注微信公众号:wwwtangshuangnet】未经授权,禁止复制转载。et 获取更多精彩内容】转载请注明出处:www.tangshua本文版权归作者所有,未经授权不得转载。【原创内容,转载请注明出处】ng.net

最后,我们通过latestState和当本文版权归作者所有,未经授权不得转载。未经授权,禁止复制转载。前的state进行对比,来猜测用户是否点【本文首发于唐霜的博客】【版权所有】唐霜 www.tangshuang.net击了“退回”按钮。

【原创内容,转载请注明出处】本文版权归作者所有,未经授权不得转载。
window.addEventListener('popstate', () => {
  const currentState = latestState;
  const { state: nextState } = history;
  latestState = nextState;

  if (currentState?.prev === nextState) {
    // 用户点击了“退回”按钮
  }
})

当变化后的state正好是变化前stat【访问 www.tangshuang.net 获取更多精彩内容】原创内容,盗版必究。e.prev时,我们就认为用户点击了“退【作者:唐霜】【版权所有】唐霜 www.tangshuang.net回”按钮。当然,这里有一个点需要提前预设本文作者:唐霜,转载请注明出处。本文作者:唐霜,转载请注明出处。,因为在不同的SPA框架中,触发pops【本文受版权保护】【原创内容,转载请注明出处】tate的可能包含在代码中调用histo【访问 www.tangshuang.net 获取更多精彩内容】转载请注明出处:www.tangshuang.netry.back()和history.go本文版权归作者所有,未经授权不得转载。转载请注明出处:www.tangshuang.net(-1)的情况,所以,在代码层面,需要继本文版权归作者所有,未经授权不得转载。转载请注明出处:www.tangshuang.net续去区分到底是程序里调用.back还是用著作权归作者所有,禁止商业用途转载。著作权归作者所有,禁止商业用途转载。户点击“退回”按钮。区分方法也很简单,你未经授权,禁止复制转载。【本文首发于唐霜的博客】可以重写back和go方法,在里面做一个【关注微信公众号:wwwtangshuangnet】【作者:唐霜】标记,从而在判断时增加对该标记的判断。

著作权归作者所有,禁止商业用途转载。本文作者:唐霜,转载请注明出处。【版权所有,侵权必究】