【问题标题】:pagehide and pageshow events don't work as expected on ios chromepagehide 和 pageshow 事件在 ios chrome 上无法正常工作
【发布时间】:2014-02-14 04:42:26
【问题描述】:

Apple 文档在此处列出了可用的 iOS 浏览器事件: https://developer.apple.com/library/archive/documentation/AppleApplications/Reference/SafariWebContent/HandlingEvents/HandlingEvents.html

“pagehide”和“pageshow”事件似乎在 safari 上运行良好,但在 chrome 上它只适用于页面加载和卸载。它不起作用:

  1. 按下主页按钮,即将 Chrome 发送到后台

  2. 切换标签

下面是一个小的 Javascript sn-p,你可以用它来验证它:

<script type="text/javascript">
        window.addEventListener("pageshow", function(evt){
            alert('show');
        }, false);
        window.addEventListener("pagehide", function(evt){
            alert('hide');
        }, false);
</script>

我可以做些什么来检测 chrome 是否被发送到后台。一旦 chrome 回到前台,我需要清除一个 setTimeout 计时器。有什么解决方法吗?

【问题讨论】:

  • 我认为您不了解“pageshow”和“pagehide”的含义。它们发生在 (a) 加载/卸载时,以及 (b) 更改页面是否是浏览器历史缓存中的当前页面(即当您导航离开或返回页面时)。它们与浏览器窗口是否可见无关。它们不适合在您的情况 (1) 和 (2) 中触发。
  • @Doin 即使我相信你的话(尽管文档链接会有所帮助),为什么行为与 Safari 不同? Safari 在我描述的场景中触发这些事件。其中至少有一个是越野车。
  • 也许在 iOS 下最小化 Safari 实际上会将页面放入历史缓存并关闭它(就像导航一样)以节省 CPU 和/或 RAM)?无论如何,一些参考:html.spec.whatwg.org/multipage/indices.html#event-pagehidedeveloper.mozilla.org/en-US/docs/Web/Events/pagehideinkling.com/read/javascript-definitive-guide-david-flanagan-6th/…; ...并且您提供的苹果链接明确指出 pagehide/show 是(nonvisual)卸载/加载事件的首选替代品。
  • 此页面详细描述了页面显示/隐藏事件背后的基本原理:developer.mozilla.org/en-US/docs/Using_Firefox_1.5_caching
  • 这些浏览器中至少有一个显示不正确(与 Web 开发不一致)的行为,因此需要特殊处理。

标签: javascript ios google-chrome dom-events


【解决方案1】:

Pagehide 和 pageshow 不是您想要完成的事情所需要的事件。

相反,将visibilitychange 事件与document.hiddendocument.visibilitystate 结合使用,这应该完全符合您的要求。

这仅适用于受支持的浏览器 - 迄今为止包括 Chrome,但不包括 Safari(目前)。所以为了安全起见,我会在visibilitychange 上调用clearTimers(),并且只有在没有定义document.visibilitystate 时才回退到在pagehide 上调用它。

见:

MDN: visibilitychange event

MDN: Using the Page Visibility API

Page Visibility - W3C recommendation, October 2013

【讨论】:

  • 页面可见性 API 对浏览器的支持很差(不太好),我不得不努力让它在所有浏览器上都能正常工作。您可以在这里找到更多详细信息:aawaara.com/post/88310470252/…
  • 在赞成这个答案之后,我发现visibilitychange 事件在 iOS Chrome 中与pageshow/pagehide 事件存在相同的问题:iOS Chrome 上没有事件被触发,例如主页按键,或深度链接到应用程序/商店。 Amit 的心跳解决方案依赖于在后台选项卡中将计时器钳制到 1000 毫秒,这似乎是一个很好的解决方法。我个人会在间隔上使用超时(间隔具有需要清除的额外开销,而 setTimeout 回调函数可能具有清除 redirectTimer 或设置新超时以再次调用自身的条件)。
  • 我收回使用setTimeout 而不是setInterval 的建议。在测试我的 setTimeout 实现期间,在 iOS Chrome 上,回到选项卡后,我的 100 毫秒“心跳”超时通常只会在我想在心跳回调中取消的 2000 毫秒计时器之后触发(通常大约 20-70 毫秒太晚了) . setInterval 实现似乎在触发长超时之前始终触发,这正是我们想要的。
【解决方案2】:

下面是工作代码:

<script type="text/javascript">
        var heartbeat;
        var lastInterval;

        function clearTimers() {
            clearTimeout(heartbeat);
        }

        function getTime() {
            return (new Date()).getTime();
        }

        function intervalHeartbeat() {
            var now = getTime();
            var diff = now - lastInterval - 200;
            lastInterval = now;
            if(diff > 1000) { // don't trigger on small stutters less than 1000ms
                clearTimers();
            }
        }
        lastInterval = getTime();
        heartbeat = setInterval(intervalHeartbeat, 200);

您可以在此处找到更多详细信息:http://aawaara.com/post/74543339755/smallest-piece-of-code-thats-going-to-change-the-world

【讨论】:

  • 这完全有效的事实(假设我相信你的话确实有效),这意味着javascript计时器不会在后台选项卡上或浏览器最小化时被触发。因此,如果您能检测到,当浏览器选项卡发送到后台而不是返回前台时,您不妨早点调用clearTimers()。另外(我假设你意识到了吗?),在任何桌面浏览器上,上述代码永远不会调用clearTimers():这些浏览器即使在后台选项卡中或最小化时也会继续运行 JS 计时器/事件/代码。
  • 它对我有用。是的,我只在 iOS 设备上通过检测服务器端来使用它。
  • 对于 iOS 上的 Chrome,这种“心跳”方法似乎是唯一可行的解​​决方案,因为 visibilitychange 不会在 iOS Chrome 上触发(类似于pageshow/pagehide 不会触发)。
猜你喜欢
  • 2015-07-13
  • 2018-04-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-01
  • 2017-10-14
  • 1970-01-01
  • 2016-09-15
相关资源
最近更新 更多