From 689a74f6eefefd40d9dbc0cbe30278cc07a42f17 Mon Sep 17 00:00:00 2001 From: omnomnom Date: Sun, 3 Aug 2025 10:50:06 +0200 Subject: [PATCH 1/3] fix(router): use pagehide for iOS navigation (fix #2536) --- packages/router/src/history/html5.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/router/src/history/html5.ts b/packages/router/src/history/html5.ts index 0f7a169a5..5e953361b 100644 --- a/packages/router/src/history/html5.ts +++ b/packages/router/src/history/html5.ts @@ -126,6 +126,10 @@ function useHistoryListeners( return teardown } + function beforeHiddenListener() { + document.hidden && beforeUnloadListener() + } + function beforeUnloadListener() { const { history } = window if (!history.state) return @@ -140,15 +144,20 @@ function useHistoryListeners( teardowns = [] window.removeEventListener('popstate', popStateHandler) window.removeEventListener('beforeunload', beforeUnloadListener) + window.removeEventListener('pagehide', beforeUnloadListener) + document.removeEventListener('visibilitychange', beforeHiddenListener) } // set up the listeners and prepare teardown callbacks window.addEventListener('popstate', popStateHandler) - // TODO: could we use 'pagehide' or 'visibilitychange' instead? // https://developer.chrome.com/blog/page-lifecycle-api/ + // note: iOS safari does not fire beforeunload, so we + // use pagehide and visibilitychange instead window.addEventListener('beforeunload', beforeUnloadListener, { passive: true, }) + window.addEventListener('pagehide', beforeUnloadListener) + document.addEventListener('visibilitychange', beforeHiddenListener) return { pauseListeners, From dc420e898a04cadf8b06a010623efce094b77cbd Mon Sep 17 00:00:00 2001 From: omnomnom Date: Sun, 3 Aug 2025 11:26:49 +0200 Subject: [PATCH 2/3] chore: removed usage of beforeunload & code cleanup --- packages/router/src/history/html5.ts | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/packages/router/src/history/html5.ts b/packages/router/src/history/html5.ts index 5e953361b..1cbfbfb59 100644 --- a/packages/router/src/history/html5.ts +++ b/packages/router/src/history/html5.ts @@ -126,9 +126,7 @@ function useHistoryListeners( return teardown } - function beforeHiddenListener() { - document.hidden && beforeUnloadListener() - } + function beforeHiddenListener() { document.hidden && beforeUnloadListener() } function beforeUnloadListener() { const { history } = window @@ -143,7 +141,6 @@ function useHistoryListeners( for (const teardown of teardowns) teardown() teardowns = [] window.removeEventListener('popstate', popStateHandler) - window.removeEventListener('beforeunload', beforeUnloadListener) window.removeEventListener('pagehide', beforeUnloadListener) document.removeEventListener('visibilitychange', beforeHiddenListener) } @@ -153,9 +150,6 @@ function useHistoryListeners( // https://developer.chrome.com/blog/page-lifecycle-api/ // note: iOS safari does not fire beforeunload, so we // use pagehide and visibilitychange instead - window.addEventListener('beforeunload', beforeUnloadListener, { - passive: true, - }) window.addEventListener('pagehide', beforeUnloadListener) document.addEventListener('visibilitychange', beforeHiddenListener) From 41831041b11781fa93209feb6fd99dd4219810ee Mon Sep 17 00:00:00 2001 From: Eduardo San Martin Morote Date: Sun, 3 Aug 2025 15:28:01 +0200 Subject: [PATCH 3/3] refactor: remove extra fn --- packages/router/src/history/html5.ts | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/router/src/history/html5.ts b/packages/router/src/history/html5.ts index 1cbfbfb59..79c5cedf0 100644 --- a/packages/router/src/history/html5.ts +++ b/packages/router/src/history/html5.ts @@ -126,15 +126,15 @@ function useHistoryListeners( return teardown } - function beforeHiddenListener() { document.hidden && beforeUnloadListener() } - function beforeUnloadListener() { - const { history } = window - if (!history.state) return - history.replaceState( - assign({}, history.state, { scroll: computeScrollPosition() }), - '' - ) + if (document.visibilityState === 'hidden') { + const { history } = window + if (!history.state) return + history.replaceState( + assign({}, history.state, { scroll: computeScrollPosition() }), + '' + ) + } } function destroy() { @@ -142,7 +142,7 @@ function useHistoryListeners( teardowns = [] window.removeEventListener('popstate', popStateHandler) window.removeEventListener('pagehide', beforeUnloadListener) - document.removeEventListener('visibilitychange', beforeHiddenListener) + document.removeEventListener('visibilitychange', beforeUnloadListener) } // set up the listeners and prepare teardown callbacks @@ -151,7 +151,7 @@ function useHistoryListeners( // note: iOS safari does not fire beforeunload, so we // use pagehide and visibilitychange instead window.addEventListener('pagehide', beforeUnloadListener) - document.addEventListener('visibilitychange', beforeHiddenListener) + document.addEventListener('visibilitychange', beforeUnloadListener) return { pauseListeners,