From 153be754a92efa5d8d7e122dcb84c8c756f8f48b Mon Sep 17 00:00:00 2001 From: cxk <119064883@qq.com> Date: Mon, 20 Jul 2026 02:43:37 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=AE=B2=E8=A7=A3=E5=88=97?= =?UTF-8?q?=E8=A1=A8=E8=BF=94=E5=9B=9E=E5=AF=BC=E8=A7=88=E9=A6=96=E9=A1=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/explain/list.vue | 35 ++++++++++++++++++------ tests/unit/ExplainListNavigation.spec.ts | 26 ++++++++++++++++++ 2 files changed, 52 insertions(+), 9 deletions(-) diff --git a/src/pages/explain/list.vue b/src/pages/explain/list.vue index 2fda1be..6adead1 100644 --- a/src/pages/explain/list.vue +++ b/src/pages/explain/list.vue @@ -79,6 +79,7 @@ type ExplainListHistoryState = { } let explainListHistoryPushed = false +let isConsumingExplainListHistory = false let isReturningToGuideHome = false type PageStackEntry = { @@ -96,6 +97,14 @@ const guideHomeUrl = () => ( shouldUseHostNavigation.value ? guideTopTabUrl('guide') : GUIDE_HOME_URL ) +const isExplainListHistoryState = (state: unknown): state is ExplainListHistoryState => ( + Boolean( + state + && typeof state === 'object' + && (state as ExplainListHistoryState).museumGuidePage === 'explain-list' + ) +) + const showGuideHomeReturnError = () => { isReturningToGuideHome = false uni.showToast({ @@ -111,8 +120,22 @@ const reLaunchGuideHome = () => { }) } +const consumeExplainListHistory = () => { + if ( + typeof window === 'undefined' + || !explainListHistoryPushed + || !isExplainListHistoryState(window.history.state) + ) return false + + // 根栈压入了同 URL 标记,先消费它,避免回首页后再次回流到讲解列表。 + isConsumingExplainListHistory = true + window.history.back() + return true +} + const returnToGuideHome = () => { - if (isReturningToGuideHome) return + if (isReturningToGuideHome || isConsumingExplainListHistory) return + if (consumeExplainListHistory()) return isReturningToGuideHome = true const pages = getPageStack() @@ -138,14 +161,6 @@ const returnToGuideHome = () => { reLaunchGuideHome() } -const isExplainListHistoryState = (state: unknown): state is ExplainListHistoryState => ( - Boolean( - state - && typeof state === 'object' - && (state as ExplainListHistoryState).museumGuidePage === 'explain-list' - ) -) - const pushExplainListHistory = () => { if (typeof window === 'undefined' || getPageStack().length > 1) return if (explainListHistoryPushed) return @@ -168,10 +183,12 @@ const handleExplainListHistoryPopState = (event: PopStateEvent) => { if (isExplainListHistoryState(event.state)) { explainListHistoryPushed = true + isConsumingExplainListHistory = false return } explainListHistoryPushed = false + isConsumingExplainListHistory = false returnToGuideHome() } diff --git a/tests/unit/ExplainListNavigation.spec.ts b/tests/unit/ExplainListNavigation.spec.ts index 3ade3f3..1836a95 100644 --- a/tests/unit/ExplainListNavigation.spec.ts +++ b/tests/unit/ExplainListNavigation.spec.ts @@ -234,6 +234,32 @@ describe('讲解展厅列表返回', () => { wrapper.unmount() }) + it('根栈页内返回先消费历史标记,再回到导览首页', async () => { + let currentHistoryState: Record = {} + vi.spyOn(window.history, 'state', 'get').mockImplementation(() => currentHistoryState) + vi.spyOn(window.history, 'pushState').mockImplementation((state) => { + currentHistoryState = (state || {}) as Record + }) + const wrapper = mountExplainList() + const historyBack = vi.spyOn(window.history, 'back').mockImplementation(() => { + currentHistoryState = {} + window.dispatchEvent(new PopStateEvent('popstate', { state: currentHistoryState })) + }) + testState.onLoadHandler?.() + + expect(window.history.state).toMatchObject({ museumGuidePage: 'explain-list' }) + + await wrapper.get('[data-testid="explain-list-back"]').trigger('click') + await flushPromises() + + expect(historyBack).toHaveBeenCalledTimes(1) + expect(uni.reLaunch).toHaveBeenCalledTimes(1) + expect(uni.reLaunch).toHaveBeenCalledWith(expect.objectContaining({ + url: '/pages/index/index?tab=guide' + })) + wrapper.unmount() + }) + it('普通 H5 浏览器返回也会回到导览首页,且不调用 history.back', async () => { const historyBack = vi.spyOn(window.history, 'back') const wrapper = mountExplainList()