fix(h5): 小程序 nh=1 原生顶栏模式与 sbh 顶距(配 202608278)

H5 在 nh=1 时隐藏 AppHeader,支持 sbh 控制内容顶距,首屏 inline 预应用。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
jackyu66git
2026-08-25 03:24:42 +08:00
co-authored by Cursor
parent 57687de360
commit 580ba85b61
6 changed files with 97 additions and 27 deletions
+2 -3
View File
@@ -17,10 +17,9 @@ import TabBar from './components/TabBar.vue'
import { isMpEmbed, isMpNativeHeader } from './lib/mpEmbed'
const mpEmbed = isMpEmbed()
const mpNativeHeader = isMpNativeHeader()
const showHeader = !mpNativeHeader
const showHeader = !isMpNativeHeader()
const shellClass = computed(() => ({
'mp-embed': mpEmbed,
'mp-native-header': mpNativeHeader,
'mp-native-header': isMpNativeHeader(),
}))
</script>
+12 -1
View File
@@ -28,7 +28,7 @@ describe('mpEmbed', () => {
expect(document.documentElement.style.getPropertyValue('--yxg-safe-top')).toBe('47px')
})
it('uses native mini-program header mode with ?nh=1', () => {
it('uses native mini-program cover header with ?nh=1', () => {
window.history.replaceState({}, '', '/psy/?mp=1&nh=1')
initMpEmbed()
expect(isMpNativeHeader()).toBe(true)
@@ -37,6 +37,17 @@ describe('mpEmbed', () => {
expect(document.documentElement.style.getPropertyValue('--yxg-page-top')).toBe('4px')
})
it('offsets content below native cover bar with ?nh=1&sbh=', () => {
window.history.replaceState({}, '', '/psy/?mp=1&nh=1&sbh=87')
initMpEmbed()
expect(isMpNativeHeader()).toBe(true)
expect(sessionStorage.getItem('yxg_sbh')).toBe('87')
expect(document.documentElement.style.getPropertyValue('--yxg-page-top')).toBe('87px')
window.history.replaceState({}, '', '/psy/?mp=1')
applyMpEmbedDom()
expect(document.documentElement.style.getPropertyValue('--yxg-page-top')).toBe('87px')
})
it('returns false without mp query', () => {
initMpEmbed()
expect(isMpEmbed()).toBe(false)
+20 -8
View File
@@ -7,12 +7,17 @@ const SBH_KEY = 'yxg_sbh'
const HEADER_H_PX = 50
const MP_CONTENT_TOP_PX = 4
/** Native cover-view handles logo; H5 only needs a tiny gap below web-view top. */
/** 小程序 cover 顶栏承载 logoH5 顶栏仅留极小间距 */
function applyNativeHeaderMode(): void {
applyNativeHeaderInset(MP_CONTENT_TOP_PX)
}
/** nh=1 且带 sbh 时,内容从原生顶栏下方开始 */
function applyNativeHeaderInset(topPx: number): void {
if (typeof document === 'undefined') return
const root = document.documentElement
root.style.setProperty('--yxg-safe-top', '0px')
root.style.setProperty('--yxg-page-top', `${MP_CONTENT_TOP_PX}px`)
root.style.setProperty('--yxg-page-top', `${topPx}px`)
}
function applySafeTopInset(px: number): void {
@@ -30,27 +35,29 @@ function readStoredSbh(): number {
return parseInt(raw, 10)
}
/** True when mini-program renders the brand header above web-view. */
export function isMpNativeHeader(): boolean {
if (typeof window === 'undefined') return false
return sessionStorage.getItem(MP_NATIVE_HEADER_KEY) === '1'
}
/** Apply document-level embed chrome (safe-area wash, hide HTML title). */
export function applyMpEmbedDom(): void {
if (typeof document === 'undefined' || !isMpEmbed()) return
document.title = '\u200b'
document.documentElement.classList.add('mp-embed')
if (isMpNativeHeader()) {
document.documentElement.classList.add('mp-native-header')
applyNativeHeaderMode()
const stored = readStoredSbh()
if (stored > 0) {
applyNativeHeaderInset(stored)
} else {
applyNativeHeaderMode()
}
return
}
const stored = readStoredSbh()
if (stored > 0) applySafeTopInset(stored)
}
/** Persist ?mp=1 from mini-program web-view entry. Call once before router mount. */
export function initMpEmbed(): void {
if (typeof window === 'undefined') return
const params = new URLSearchParams(window.location.search)
@@ -59,7 +66,13 @@ export function initMpEmbed(): void {
}
if (params.get(NH_QUERY) === '1') {
sessionStorage.setItem(MP_NATIVE_HEADER_KEY, '1')
applyNativeHeaderMode()
const nativeSbh = params.get(SBH_QUERY)
if (nativeSbh && /^\d+$/.test(nativeSbh)) {
sessionStorage.setItem(SBH_KEY, nativeSbh)
applyNativeHeaderInset(parseInt(nativeSbh, 10))
} else {
applyNativeHeaderMode()
}
}
if (!isMpNativeHeader()) {
const sbh = params.get(SBH_QUERY)
@@ -71,7 +84,6 @@ export function initMpEmbed(): void {
applyMpEmbedDom()
}
/** True when H5 runs inside WeChat mini-program web-view (no H5 tab bar). */
export function isMpEmbed(): boolean {
if (typeof window === 'undefined') return false
return sessionStorage.getItem(MP_EMBED_KEY) === '1'
+8
View File
@@ -64,6 +64,14 @@ html.mp-embed body{
padding-top:var(--yxg-page-top);
min-height:100%;
}
html.mp-embed.mp-native-header .app-shell .home,
html.mp-embed.mp-native-header .app-shell .ps,
html.mp-embed.mp-native-header .app-shell .yxg-page{
padding-top:var(--yxg-page-top);
}
html.mp-embed.mp-native-header .app-header{
display:none !important;
}
.app-footer{
position:relative;
z-index:1;