资讯专栏INFORMATION COLUMN

ios下popstate触发的问题

loostudy / 2731人阅读

摘要:去查看一下的源码,发现被改装了,监听的回调回在事件触发的时候触发。搞清楚的触发机制根据的描述当活动历史记录条目更改时,将触发事件。说明了上,依旧不能阻止的触发。最终解决由于刷新重新加载是肯定不会触发的,所以可以后进行。

背景:

在使用Tarojs开发的时候,发现在ios上跳转至其他页面,再返回回来会出现接口接连调用两次的情况。

排查过程:

1.由于接口调用在组件的didMount里,所以看其他的组件也是didMount调用两次,这让我感觉很诧异,componentDidMount这个生命周期应该不会调用两次的;

2.我打开了weinre查看,发现了有两个一模一样的页面组件,如下图

因为是router层级上double了,所以所有组件都会实例化两次,此时我怀疑是taro/router的问题。

我又去看了一下果园是否也是有同样的情况,结果发现在page componentDidMount里调用的tree/get等首屏数据接口调用了两次。。。

去查看一下@tarojs/router的源码,发现

history被tarojs/router改装了,history.listen监听的回调回在popstate事件触发的时候触发。

现在的问题根源确定了是由于popstate事件的触发,导致了tarojs/router认为当前页面是进行了一次前端路由跳转,所以进行了两次页面级别的渲染,导致所有的组件实例的生命周期都走了两次。那么问题来了,明明我们根本没有利用history的特性,所有的跳转都是刷新式跳转,为什么这个popstate会触发呢。

3.搞清楚popstate的触发机制

根据MDN的描述:

当活动历史记录条目更改时,将触发popstate事件。如果被激活的历史记录条目是通过对history.pushState()的调用创建的,或者受到对history.replaceState()的调用的影响,popstate事件的state属性包含历史条目的状态对象的副本。

需要注意的是调用history.pushState()或history.replaceState()不会触发popstate事件。只有在做出浏览器动作时,才会触发该事件,如用户点击浏览器的回退按钮(或者在Javascript代码中调用history.back())

理论上popstate是不会在我们的应用了触发的,我试验了一下这个东西究竟是何方神圣。

var a = document.getElementById("a");

a.onclick = function() {

  location.href = "/aaa.html"

}

window.addEventListener(‘popstate’, function handlePopState() {

  console.log("handlePopState")

}, false);

点击后返回,压根没有触发popstate,不管在ios还是android上。

然后我将

location.href = ‘/aaa.html"

替换成

history.replaceState(null, "", "aaa.html");

在ios上返回是无刷新式的返回,触发了popstate事件,仅仅url回退成popstate.html。

在android上返回是刷新式返回,同样触发了popstate事件,然后会重新解析/加载/执行。

到这里已经确定了location.href的跳转后返回是不会触发popstate的,因为是刷新式的返回,那就是我们在业务里有动了history的api,此时我怀疑是在业务底层代码使用了history。

4.查看业务底层跳转代码

看到navigation.forward在H5仅仅使用了location.href进行跳转,但是在此之前为了加is_back参数表示当前页面是通过回退到达的,使用了history.replaceState。

我模拟一下这个操作

var a = document.getElementById("a");

a.onclick = function() {

  history.replaceState(null, "", "popstate33.html?a=1");

  location.href = "/aaa.html"

}

果不其然,在ios里在返回的时候会触发popstate事件,而android不会触发。

说明了ios上,依旧不能阻止popstate的触发。

5.解决方案

由于在ios中返回页面会触发popstate,在tarojs/router此时认为进行了一次前端路由

5.1 在进入页面后根据is_back进行一次reload

5.2 在底层跳转代码包上进行再一次包装,跳转的时候不再使用history.replaceState

然而。。。。。。。

tarojs/router有这么一行- -,也就是业务层不使用history.replaceState,它自己本身也用了,我把这行注释掉,且业务上不使用replaceState,ios回退才不会触发popstate。

所以。。。。

5.1由于不能使用replaceState将is_back去掉,不然将无限循环刷新;

5.2由于tarojs/router本身自己使用了history.replaceState,也没有了意义。

一切又回到了起点。。。。

最终解决


由于刷新重新加载是肯定不会触发popstate的,所以可以replaceState后进行reload。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/106161.html

相关文章

  • 在单页应用中,如何优雅监听url变化

    摘要:单页应用的原理从早起的根据的变化,到根据的的变化,实现无刷新条件下的页面重新渲染。那么在单页应用中是如何监听的变化呢,本文将总结一下,如何在单页页面中优雅的监听的变化。在下几章中,重点介绍一下如何监听的改变。   单页应用的原理从早起的根据url的hash变化,到根据H5的history的变化,实现无刷新条件下的页面重新渲染。那么在单页应用中是如何监听url的变化呢,本文将总结一下,...

    leap_frog 评论0 收藏0
  • 在单页应用中,如何优雅监听url变化

    摘要:单页应用的原理从早起的根据的变化,到根据的的变化,实现无刷新条件下的页面重新渲染。那么在单页应用中是如何监听的变化呢,本文将总结一下,如何在单页页面中优雅的监听的变化。在下几章中,重点介绍一下如何监听的改变。   单页应用的原理从早起的根据url的hash变化,到根据H5的history的变化,实现无刷新条件下的页面重新渲染。那么在单页应用中是如何监听url的变化呢,本文将总结一下,...

    姘存按 评论0 收藏0
  • 在单页应用中,如何优雅监听url变化

    摘要:单页应用的原理从早起的根据的变化,到根据的的变化,实现无刷新条件下的页面重新渲染。那么在单页应用中是如何监听的变化呢,本文将总结一下,如何在单页页面中优雅的监听的变化。在下几章中,重点介绍一下如何监听的改变。   单页应用的原理从早起的根据url的hash变化,到根据H5的history的变化,实现无刷新条件下的页面重新渲染。那么在单页应用中是如何监听url的变化呢,本文将总结一下,...

    zhkai 评论0 收藏0
  • 历史记录API中hashchange与popstate比较

    摘要:与事件都是浏览器历史记录,两者都是中的,相对而言比更为强大。事件本身只是监测的变化,我认为目前其主要意义就是与搭配使用从而使得在下历史记录前进后退按钮依然有效。地址新的历史记录条目的地址。 hashchange与popstate事件都是浏览器历史记录API,两者都是HTML5中的API,相对而言popstate比hashchange更为强大。注意这两种历史记录管理都受同源策略的限制,这...

    Yangder 评论0 收藏0
  • 使用history保存列表页ajax请求状态

    摘要:问题最近碰到两个问题从首页进入列表页之后,点击下一页的时候,使用请求更新数据,然后点击浏览器后退按钮就直接返回到首页,实际这里想要的效果是返回列表页上一页。没法记住之前分页状态。 问题 最近碰到两个问题: 从首页进入列表页之后,点击下一页的时候,使用ajax请求更新数据, 然后点击浏览器后退按钮就直接返回到首页,实际这里想要的效果是返回列表页上一页。 在列表页分页为2的页面进入详情页,...

    amuqiao 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<