web-dev-qa-db-fra.com

Existe-t-il un moyen d'utiliser window.onbeforeunload sur Mobile Safari pour les appareils iOS?

On dirait que Apple a désactivé l'événement window.onbeforeunload pour les appareils iOS (iPhone, iPad, iPod Touch). Malheureusement, je ne trouve aucune documentation expliquant pourquoi cet événement ne fonctionne pas dans Mobile Safari.

Est-ce que quelqu'un sait s'il existe une alternative fiable à cette fonction? Le navigateur d'Android semble le prendre en charge très bien, et l'application de bureau Safari prend également en charge l'événement onbeforeunload sans problème.

42
8three

Je vois que c'est une vieille question, mais j'ai rencontré ce problème récemment.

J'utilise window.unload et cela fonctionne très bien dans les navigateurs ios (bien que si vous regardez documentation Apple cela semble obsolète et ils recommandent d'utiliser document.pagehide)

19
Miquel

Si vous en avez vraiment besoin, vous ne pouvez pas obtenir tous les liens, formulaires et objets DOM qui ont un gestionnaire changeant l'URL et les faire attendre jusqu'à ce que vous ayez fait ce que vous voulez. Pour les liens, vous les obtenez par getElementsByTagName, vérifiez si le href commence par autre chose qu'un # et ajoutez simplement votre fonction onbeforeunload add onclick (qui sera invoquée avant que le href ne soit examiné). Idem pour les formulaires mais avec onsubmit. Et enfin, pour les éléments changeant le href avec JavaScript, vous devez vous assurer que lorsque vous ajoutez le lsitener que vous appelez votre fonction onbeforeunlaod (ou, si vous utilisez des écouteurs DOM0 ou DOM1, vous pouvez simplement ajouter une classe puis utiliser un script global qui vérifie tous les éléments avec la classe et l'ajoute à l'écouteur d'événements avec une fermeture.

Mais vous devriez normalement pouvoir éviter l'utilisation de cet événement (probablement en utilisant des cookies pour stocker la chose que vous vouliez envoyer toutes les x secondes et en permettant, dans le pire des cas, d'y jeter un œil la prochaine fois que l'utilisateur charge une page et , dans le meilleur des cas, pouvoir envoyer une requête Ajax à onbeforeunload ou onunload qui, même si elle n'envoie que les en-têtes http, vous permettra d'obtenir ce que vous voulez).

1
xavierm02

Sur la base de la réponse de Xavier, j'ai imaginé une solution dans ce sens:

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);
}

Cette solution présente certaines limites. Le plus important est qu'il s'attache aux formulaires tous et à tous les liens. Parfois, cela peut ne pas être souhaité. Si vous en avez besoin, vous pouvez ignorer certains nœuds (par exemple, marquez-les avec un data- attribut).

0
Motine