修复小程序内嵌页面标题同步
Some checks failed
CI / verify (push) Has been cancelled

This commit is contained in:
lyf
2026-07-27 19:56:53 +08:00
parent 9ea1bfab71
commit f1047414bb
6 changed files with 113 additions and 3 deletions

View File

@@ -25,7 +25,7 @@
{ {
"path": "pages/explain/list", "path": "pages/explain/list",
"style": { "style": {
"navigationBarTitleText": "全部讲解", "navigationBarTitleText": "免费讲解",
"navigationBarBackgroundColor": "#FFFFFF", "navigationBarBackgroundColor": "#FFFFFF",
"navigationStyle": "custom" "navigationStyle": "custom"
} }

View File

@@ -10,7 +10,6 @@
<ExplainHallSelect <ExplainHallSelect
:halls="explainHallItems" :halls="explainHallItems"
stage="hall" stage="hall"
force-internal-header
:loading="explainLoading" :loading="explainLoading"
:error="explainError" :error="explainError"
@hall-click="handleExplainHallClick" @hall-click="handleExplainHallClick"
@@ -40,6 +39,7 @@ import {
type GuideTopTab type GuideTopTab
} from '@/utils/guideTopTabs' } from '@/utils/guideTopTabs'
import { isEmbeddedInWechatMiniProgram } from '@/utils/hostEnvironment' import { isEmbeddedInWechatMiniProgram } from '@/utils/hostEnvironment'
import { syncHostNavigationTitle } from '@/utils/hostNavigationTitle'
import { explainGuideStopListUrl } from '@/utils/explainNavigation' import { explainGuideStopListUrl } from '@/utils/explainNavigation'
const explainHallItems = ref<ExplainHallSelectItem[]>([]) const explainHallItems = ref<ExplainHallSelectItem[]>([])
@@ -218,6 +218,7 @@ const loadExplainHalls = async () => {
} }
onLoad(() => { onLoad(() => {
syncHostNavigationTitle('免费讲解')
pushExplainListHistory() pushExplainListHistory()
void loadExplainHalls() void loadExplainHalls()
}) })

View File

@@ -276,6 +276,7 @@ import {
type GuideTopTab type GuideTopTab
} from '@/utils/guideTopTabs' } from '@/utils/guideTopTabs'
import { isEmbeddedInWechatMiniProgram } from '@/utils/hostEnvironment' import { isEmbeddedInWechatMiniProgram } from '@/utils/hostEnvironment'
import { syncHostNavigationTitle } from '@/utils/hostNavigationTitle'
import { import {
guideUseCase guideUseCase
} from '@/usecases/guideUseCase' } from '@/usecases/guideUseCase'
@@ -419,6 +420,14 @@ let pendingPoiDetailUiContext: Readonly<{
// 状态 // 状态
const currentTab = ref<GuideTopTab>(initialTopTab()) const currentTab = ref<GuideTopTab>(initialTopTab())
const topTabNavigationTitle = (tab: GuideTopTab) => (
tab === 'explain' ? '免费讲解' : '地图导览'
)
watch(currentTab, (tab) => {
syncHostNavigationTitle(topTabNavigationTitle(tab))
}, { immediate: true })
const launchOverlayVisible = ref(shouldShowLaunchOverlay()) const launchOverlayVisible = ref(shouldShowLaunchOverlay())
const launchOverlayLeaving = ref(false) const launchOverlayLeaving = ref(false)
const launchProgress = ref(8) const launchProgress = ref(8)

View File

@@ -0,0 +1,39 @@
import { isEmbeddedInWechatMiniProgram } from '@/utils/hostEnvironment'
export const MINI_PROGRAM_NAVIGATION_TITLE_MESSAGE = 'museum-guide:navigation-title'
type MiniProgramBridge = {
postMessage?: (options: {
data: {
type: typeof MINI_PROGRAM_NAVIGATION_TITLE_MESSAGE
title: string
}
}) => void
}
const getMiniProgramBridge = () => {
if (typeof window === 'undefined') return undefined
return (window as Window & {
wx?: {
miniProgram?: MiniProgramBridge
}
}).wx?.miniProgram
}
export const syncHostNavigationTitle = (title: string) => {
if (typeof document !== 'undefined') document.title = title
if (typeof uni !== 'undefined' && typeof uni.setNavigationBarTitle === 'function') {
uni.setNavigationBarTitle({ title })
}
if (!isEmbeddedInWechatMiniProgram()) return
getMiniProgramBridge()?.postMessage?.({
data: {
type: MINI_PROGRAM_NAVIGATION_TITLE_MESSAGE,
title
}
})
}

View File

@@ -112,7 +112,7 @@ describe('讲解展厅列表返回', () => {
window.history.replaceState({}, '', window.location.href) window.history.replaceState({}, '', window.location.href)
const wrapper = mountExplainList() const wrapper = mountExplainList()
expect(wrapper.getComponent(ExplainHallSelectStub).props('forceInternalHeader')).toBe(true) expect(wrapper.getComponent(ExplainHallSelectStub).props('forceInternalHeader')).toBe(false)
await wrapper.get('[data-testid="explain-list-back"]').trigger('click') await wrapper.get('[data-testid="explain-list-back"]').trigger('click')
expect(uni.navigateBack).not.toHaveBeenCalled() expect(uni.navigateBack).not.toHaveBeenCalled()

View File

@@ -0,0 +1,61 @@
// @vitest-environment happy-dom
import { afterEach, describe, expect, it, vi } from 'vitest'
import {
MINI_PROGRAM_NAVIGATION_TITLE_MESSAGE,
syncHostNavigationTitle
} from '@/utils/hostNavigationTitle'
const hostEnvironmentMocks = vi.hoisted(() => ({
embeddedInWechatMiniProgram: false
}))
vi.mock('@/utils/hostEnvironment', () => ({
isEmbeddedInWechatMiniProgram: () => hostEnvironmentMocks.embeddedInWechatMiniProgram
}))
afterEach(() => {
hostEnvironmentMocks.embeddedInWechatMiniProgram = false
vi.unstubAllGlobals()
})
describe('小程序宿主标题同步', () => {
it('嵌入态同步免费讲解标题并通知小程序宿主', () => {
const postMessage = vi.fn()
const setNavigationBarTitle = vi.fn()
hostEnvironmentMocks.embeddedInWechatMiniProgram = true
vi.stubGlobal('uni', { setNavigationBarTitle })
vi.stubGlobal('window', {
...window,
wx: {
miniProgram: { postMessage }
}
})
syncHostNavigationTitle('免费讲解')
expect(document.title).toBe('免费讲解')
expect(setNavigationBarTitle).toHaveBeenCalledWith({ title: '免费讲解' })
expect(postMessage).toHaveBeenCalledWith({
data: {
type: MINI_PROGRAM_NAVIGATION_TITLE_MESSAGE,
title: '免费讲解'
}
})
})
it('非嵌入态不向小程序桥接发送标题', () => {
const postMessage = vi.fn()
vi.stubGlobal('window', {
...window,
wx: {
miniProgram: { postMessage }
}
})
syncHostNavigationTitle('免费讲解')
expect(document.title).toBe('免费讲解')
expect(postMessage).not.toHaveBeenCalled()
})
})