web-dev-qa-db-ja.com

iOSデバイスのMobile Safariでwindow.onbeforeunloadを使用する方法はありますか?

Appleにより、iOSデバイス(iPhone、iPad、iPod Touch)のwindow.onbeforeunloadイベントが無効になりました。残念ながら、このイベントがモバイルで機能しない理由に関するドキュメントは見つかりません。サファリ。

この機能の信頼できる代替手段があるかどうか誰かが知っていますか? Androidのブラウザーはそれをうまくサポートしているように見え、Safariデスクトップアプリケーションも問題なくonbeforeunloadイベントをサポートしています。

42
8three

古い質問だと思いますが、最近この問題に直面しました。

私はwindow.unloadを使用しており、iOSブラウザで正常に動作します(ただし、 Appleのドキュメント を参照すると、非推奨のようで、推奨されていますdocument.pagehide)を使用する

19
Miquel

本当に必要な場合は、URLを変更するハンドラーを持つすべてのリンク、フォーム、およびDOMオブジェクトを取得して、必要なことが完了するまでそれらを待機させることはできません。リンクについては、getElementsByTagNameで取得し、hrefが#以外で始まるかどうかを確認し、onbeforeunload関数add onclick(hrefが見られる前に呼び出される)を追加するだけです。フォームも同じですが、onsubmitを使用します。そして最後に、JavaScriptでhrefを変更する要素については、onbeforeunlaod関数を呼び出すlsitenerを追加するときに確認する必要があります(または、DOM0またはDOM1リスナーを使用する場合は、クラスを追加してからグローバルスクリプトを使用できますこれは、クラスを使用してすべての要素をチェックし、クロージャーでイベントリスナーに追加します。

ただし、通常はこのイベントの使用を回避できるはずです(おそらくCookieを使用して、x秒ごとに送信したいものを保存し、最悪の場合、ユーザーが次にページをロードしたときにそれを確認できるようにします。 、最良のケースでは、onbeforeunloadまたはonunloadでAjaxリクエストを送信できるようにします。これにより、httpヘッダーのみを送信する場合でも、woudlは必要なものを取得できます。

1
xavierm02

ザビエルの答えに基づいて、私はこれらの線に沿って解決策を考案しました:

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

このソリューションにはいくつかの制限があります。最大のものは、それがallフォームとすべてのリンクにアタッチされることです。これは望ましくない場合があります。必要な場合は、一部のノードをスキップできます(たとえば、特定のdata-属性でノードをマークします)。

0
Motine