fix(h5): 修复 WebView 顶栏 logo 与内容重叠
embed 模式 header 改文档流、移除负 margin;持久化 sbh 并在路由中保留,避免胶囊区与档案条重叠。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<header class="app-header">
|
<header class="app-header" :class="{ 'is-embed': mpEmbed }">
|
||||||
<div class="side left">
|
<div class="side left">
|
||||||
<BackButton v-if="showBack" />
|
<BackButton v-if="showBack" />
|
||||||
</div>
|
</div>
|
||||||
@@ -15,8 +15,10 @@ import { computed } from 'vue'
|
|||||||
import { useRoute } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
import BackButton from './BackButton.vue'
|
import BackButton from './BackButton.vue'
|
||||||
import BrandLogo from './BrandLogo.vue'
|
import BrandLogo from './BrandLogo.vue'
|
||||||
|
import { isMpEmbed } from '../lib/mpEmbed'
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
|
const mpEmbed = isMpEmbed()
|
||||||
|
|
||||||
/** 首页 / 我的 为 Tab 根页不显示返回;探索可从首页进入,显示返回 */
|
/** 首页 / 我的 为 Tab 根页不显示返回;探索可从首页进入,显示返回 */
|
||||||
const showBack = computed(() => {
|
const showBack = computed(() => {
|
||||||
@@ -40,6 +42,11 @@ const showBack = computed(() => {
|
|||||||
background: transparent;
|
background: transparent;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
.app-header.is-embed {
|
||||||
|
position: relative;
|
||||||
|
padding: calc(6px + var(--yxg-safe-top)) 12px 8px;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
.side {
|
.side {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|||||||
@@ -35,16 +35,14 @@ withDefaults(
|
|||||||
.ps {
|
.ps {
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
margin-top: calc(-1 * var(--yxg-safe-top));
|
|
||||||
padding-top: var(--yxg-page-top);
|
padding-top: var(--yxg-page-top);
|
||||||
padding-bottom: var(--spacing-xs);
|
padding-bottom: var(--spacing-xs);
|
||||||
min-height: calc(100% + var(--yxg-safe-top));
|
min-height: 100%;
|
||||||
background: var(--yxg-page-wash);
|
background: var(--yxg-page-wash);
|
||||||
}
|
}
|
||||||
.ps-flat {
|
.ps-flat {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
margin-top: calc(-1 * var(--yxg-safe-top));
|
|
||||||
padding-top: var(--yxg-page-top);
|
padding-top: var(--yxg-page-top);
|
||||||
}
|
}
|
||||||
.atm {
|
.atm {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { afterEach, beforeEach, describe, expect, it } from 'vitest'
|
import { afterEach, beforeEach, describe, expect, it } from 'vitest'
|
||||||
import { initMpEmbed, isMpEmbed } from './mpEmbed'
|
import { applyMpEmbedDom, initMpEmbed, isMpEmbed } from './mpEmbed'
|
||||||
|
|
||||||
describe('mpEmbed', () => {
|
describe('mpEmbed', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
@@ -17,11 +17,15 @@ describe('mpEmbed', () => {
|
|||||||
expect(isMpEmbed()).toBe(true)
|
expect(isMpEmbed()).toBe(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('applies status bar height from ?sbh=', () => {
|
it('persists status bar height from ?sbh=', () => {
|
||||||
window.history.replaceState({}, '', '/psy/?mp=1&sbh=47')
|
window.history.replaceState({}, '', '/psy/?mp=1&sbh=47')
|
||||||
initMpEmbed()
|
initMpEmbed()
|
||||||
expect(document.documentElement.style.getPropertyValue('--yxg-safe-top')).toBe('47px')
|
expect(document.documentElement.style.getPropertyValue('--yxg-safe-top')).toBe('47px')
|
||||||
expect(document.documentElement.style.getPropertyValue('--yxg-page-top')).toBe('calc(47px + 50px)')
|
expect(document.documentElement.style.getPropertyValue('--yxg-page-top')).toBe('calc(47px + 50px)')
|
||||||
|
expect(sessionStorage.getItem('yxg_sbh')).toBe('47')
|
||||||
|
window.history.replaceState({}, '', '/psy/?mp=1')
|
||||||
|
applyMpEmbedDom()
|
||||||
|
expect(document.documentElement.style.getPropertyValue('--yxg-safe-top')).toBe('47px')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('returns false without mp query', () => {
|
it('returns false without mp query', () => {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
const MP_EMBED_KEY = 'yxg_mp_embed'
|
const MP_EMBED_KEY = 'yxg_mp_embed'
|
||||||
const MP_QUERY = 'mp'
|
const MP_QUERY = 'mp'
|
||||||
const SBH_QUERY = 'sbh'
|
const SBH_QUERY = 'sbh'
|
||||||
|
const SBH_KEY = 'yxg_sbh'
|
||||||
const HEADER_H_PX = 50
|
const HEADER_H_PX = 50
|
||||||
|
|
||||||
function applySafeTopInset(px: number): void {
|
function applySafeTopInset(px: number): void {
|
||||||
@@ -11,11 +12,20 @@ function applySafeTopInset(px: number): void {
|
|||||||
root.style.setProperty('--yxg-page-top', `calc(${safe} + ${HEADER_H_PX}px)`)
|
root.style.setProperty('--yxg-page-top', `calc(${safe} + ${HEADER_H_PX}px)`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function readStoredSbh(): number {
|
||||||
|
if (typeof sessionStorage === 'undefined') return 0
|
||||||
|
const raw = sessionStorage.getItem(SBH_KEY)
|
||||||
|
if (!raw || !/^\d+$/.test(raw)) return 0
|
||||||
|
return parseInt(raw, 10)
|
||||||
|
}
|
||||||
|
|
||||||
/** Apply document-level embed chrome (safe-area wash, hide HTML title). */
|
/** Apply document-level embed chrome (safe-area wash, hide HTML title). */
|
||||||
export function applyMpEmbedDom(): void {
|
export function applyMpEmbedDom(): void {
|
||||||
if (typeof document === 'undefined' || !isMpEmbed()) return
|
if (typeof document === 'undefined' || !isMpEmbed()) return
|
||||||
document.title = '\u200b'
|
document.title = '\u200b'
|
||||||
document.documentElement.classList.add('mp-embed')
|
document.documentElement.classList.add('mp-embed')
|
||||||
|
const stored = readStoredSbh()
|
||||||
|
if (stored > 0) applySafeTopInset(stored)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Persist ?mp=1 from mini-program web-view entry. Call once before router mount. */
|
/** Persist ?mp=1 from mini-program web-view entry. Call once before router mount. */
|
||||||
@@ -27,6 +37,7 @@ export function initMpEmbed(): void {
|
|||||||
}
|
}
|
||||||
const sbh = params.get(SBH_QUERY)
|
const sbh = params.get(SBH_QUERY)
|
||||||
if (sbh && /^\d+$/.test(sbh)) {
|
if (sbh && /^\d+$/.test(sbh)) {
|
||||||
|
sessionStorage.setItem(SBH_KEY, sbh)
|
||||||
applySafeTopInset(parseInt(sbh, 10))
|
applySafeTopInset(parseInt(sbh, 10))
|
||||||
}
|
}
|
||||||
applyMpEmbedDom()
|
applyMpEmbedDom()
|
||||||
|
|||||||
@@ -48,10 +48,9 @@ const {
|
|||||||
.home {
|
.home {
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
margin-top: calc(-1 * var(--yxg-safe-top));
|
|
||||||
padding-top: var(--yxg-page-top);
|
padding-top: var(--yxg-page-top);
|
||||||
padding-bottom: var(--spacing-xs);
|
padding-bottom: var(--spacing-xs);
|
||||||
min-height: calc(100% + var(--yxg-safe-top));
|
min-height: 100%;
|
||||||
background: var(--yxg-page-wash);
|
background: var(--yxg-page-wash);
|
||||||
}
|
}
|
||||||
.atm {
|
.atm {
|
||||||
|
|||||||
@@ -50,8 +50,20 @@ const router = createRouter({
|
|||||||
})
|
})
|
||||||
|
|
||||||
router.beforeEach((to) => {
|
router.beforeEach((to) => {
|
||||||
if (!isMpEmbed() || to.query.mp === '1') return true
|
if (!isMpEmbed()) return true
|
||||||
return { path: to.path, query: { ...to.query, mp: '1' }, hash: to.hash, replace: true }
|
const q = { ...to.query }
|
||||||
|
let changed = false
|
||||||
|
if (q.mp !== '1') {
|
||||||
|
q.mp = '1'
|
||||||
|
changed = true
|
||||||
|
}
|
||||||
|
const storedSbh = sessionStorage.getItem('yxg_sbh')
|
||||||
|
if (storedSbh && q.sbh !== storedSbh) {
|
||||||
|
q.sbh = storedSbh
|
||||||
|
changed = true
|
||||||
|
}
|
||||||
|
if (!changed) return true
|
||||||
|
return { path: to.path, query: q, hash: to.hash, replace: true }
|
||||||
})
|
})
|
||||||
|
|
||||||
export default router
|
export default router
|
||||||
|
|||||||
@@ -52,15 +52,18 @@ html.mp-embed body{
|
|||||||
.app-shell.mp-embed::before{
|
.app-shell.mp-embed::before{
|
||||||
content:"";
|
content:"";
|
||||||
position:fixed;
|
position:fixed;
|
||||||
top:calc(-1 * var(--yxg-safe-top));
|
inset:0;
|
||||||
left:0;
|
|
||||||
right:0;
|
|
||||||
bottom:0;
|
|
||||||
z-index:0;
|
z-index:0;
|
||||||
pointer-events:none;
|
pointer-events:none;
|
||||||
background:var(--yxg-body-wash);
|
background:var(--yxg-body-wash);
|
||||||
background-color:var(--color-bg-start);
|
background-color:var(--color-bg-start);
|
||||||
}
|
}
|
||||||
|
.app-shell.mp-embed .home,
|
||||||
|
.app-shell.mp-embed .ps{
|
||||||
|
margin-top:0;
|
||||||
|
padding-top:8px;
|
||||||
|
min-height:100%;
|
||||||
|
}
|
||||||
.app-footer{
|
.app-footer{
|
||||||
position:relative;
|
position:relative;
|
||||||
z-index:1;
|
z-index:1;
|
||||||
|
|||||||
Reference in New Issue
Block a user