有没有办法在iOS设备的Mobile Safari上使用window.onbeforeunload?

48

看起来苹果已经禁用了iOS设备(iPhone、iPad、iPod Touch)上的window.onbeforeunload事件。不幸的是,我找不到任何关于为什么Mobile Safari无法使用此事件的文档。

有没有人知道是否有可靠的替代方法?Android的浏览器似乎完全支持它,而Safari桌面应用程序也可以正常支持onbeforeunload事件。


这是 window.onbeforeunload not working on the iPad? 的副本。 - Peter V. Mørch
这个回答解决了你的问题吗?window.onbeforeunload在iPad上无法工作? - miken32
4个回答

20

我看到这是一个老问题,但最近我也遇到了这个问题。

我正在使用 window.unload,在 iOS 浏览器中它可以正常工作(尽管如果您查看 苹果文档,它似乎已经被弃用,他们推荐使用 document.pagehide)。


13
当用户重新加载页面时,似乎在iOS 9上pagehide和unload都无法工作。 - CpnCrunch
2
那么...我们要用什么? :) - diegocr

2

根据Xavier的答案,我设计了以下解决方案:

function doStuff() {
  // here goes your logic
}

function isSafariMobile() {
  return navigator && /Safari/.test(navigator.userAgent) && /iPhone|iPad/.test(navigator.userAgent)
}

function addWatcherToLinks(baseNode) {
  if (!baseNode || !baseNode.querySelectorAll) { return; } // ignore comments, text, etc.
  for (const link of baseNode.querySelectorAll("a")) {
    link.addEventListener('click', doStuff);
  }
  for (const form of baseNode.querySelectorAll("form")) {
    form.addEventListener('submit', doStuff);
  }
}

// ...when the page loads...
// we watch the page for beforeunload to call doStuff
// Since Safari mobile does not support this, we attach a listener (watcher) to each link and form and then call doStuff.
// Also, we add such a watcher to all new incoming nodes (DOMNodeInserted).
if (isSafariMobile()) {
  addWatcherToLinks(document);
  window.addEventListener("DOMNodeInserted", (event) => { addWatcherToLinks(event.target); }, false);
} else {
  window.addEventListener('beforeunload', doStuff);
}

这个解决方案有一些限制。最大的限制是它会附加到所有表单和链接上。有时这可能不是所需的。如果需要,您可以跳过某些节点(例如,使用特定的data-属性标记它们)。


2
如果你真的需要它,你可以获取所有链接、表单和DOM对象,这些对象具有更改URL的处理程序,并使它们等待直到你完成想要的操作。对于链接,你可以通过getElementsByTagName获取它们,检查href是否以#开头,然后添加onbeforeunload函数的onclick(在查看href之前调用)。对于表单也是如此,但使用onsubmit。最后,对于使用JavaScript更改href的元素,你应该确保在添加侦听器时调用onbeforeunload函数(或者,如果你使用DOM0或DOM1侦听器,可以只添加一些类,然后使用全局脚本检查所有带有类的元素并将其添加到事件侦听器中)。但通常情况下,你应该能够避免使用此事件(可能使用cookie每x秒存储要发送的内容,并允许在最坏的情况下在用户加载页面时查看它,在最好的情况下能够在onbeforeunload或onunload时发送Ajax请求,即使仅发送http标头,也可以获取你想要的内容)。

谢谢Xavier,虽然这些都是可能的解决方案,但在我的应用程序中,它们都需要进行大量的DOM修改,这是不可行的,因为它可能会干扰托管页面的功能。 - Jim Blackler
你不需要在每个链接上都添加事件等,可以使用事件委托。只需在body上放置一个事件,并使用e.srcElement || e.target,然后检查它是否会更改URL。这样,您就不需要放置那么多元素。但是,您可能仍然需要将onsubmit放在表单本身上...对此不太确定。 - xavierm02
1
有没有任何选项适用于用户实际关闭页面的情况,而不是通过元素转到另一页? - Edwin Daniels
不行。如果它在计算机上,你可以检测到鼠标离开窗口并做好准备。最好的方法可能是一直告诉服务器“我还在这里”,这样当你没有离开时,它就能推断出你已经离开了,从而设置服务器超时。也许最好使用WebSockets来代替许多Ajax调用。除此之外,我能想到的唯一办法就是强制用户始终保持某个焦点,并在onblur时发送消息(也许在其后添加一个小的while true)。无论如何,没有什么方法可以在不惹恼用户的情况下使用。 - xavierm02

0

我曾经遇到过同样的问题。似乎iPhone上的Safari浏览器只会触发焦点和失焦事件,而几乎所有其他事件都不会被触发,例如(pagehide、pageshow、可见性更改),但好消息是焦点和失焦事件也支持并在iPhone、iPad和Android手机上触发。

    window.addEventListener('focus', function(){
       // do stuff
     });

   window.addEventListener('blur', function(){
       // do stuff
     });

希望这能帮到任何人。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接