diff --git a/src/App.vue b/src/App.vue index 4c1eb6c2..3e09f2be 100644 --- a/src/App.vue +++ b/src/App.vue @@ -610,6 +610,12 @@ page { @import url('./static/icon/self/iconfont.css'); // #ifdef H5 +:root { + --native-status-bar-height: env(safe-area-inset-top, 0px); + --app-shell-status-bar-height: 0px; + --status-bar-height: var(--native-status-bar-height); +} + html, body, #app, @@ -633,8 +639,8 @@ uni-page-wrapper { display: flex; flex-direction: column; // #ifdef H5 - height: calc(100dvh - 50px - $im-nav-bar-height); // h5平台100vh是包含了底部高度,需要减去 - top: $im-nav-bar-height; + height: calc(100dvh - 50px - $im-nav-bar-height - var(--status-bar-height, 0px)); // h5套壳时还要减去宿主app状态栏高度 + top: calc($im-nav-bar-height + var(--status-bar-height, 0px)); overflow: hidden; min-height: 0; // #endif @@ -657,8 +663,8 @@ uni-page-wrapper { .page { position: relative; // #ifdef H5 - height: calc(100vh - $im-nav-bar-height); // h5平台100vh是包含了底部高度,需要减去 - top: $im-nav-bar-height; + height: calc(100dvh - $im-nav-bar-height - var(--status-bar-height, 0px)); // h5套壳时还要减去宿主app状态栏高度 + top: calc($im-nav-bar-height + var(--status-bar-height, 0px)); overflow: hidden; min-height: 0; // #endif diff --git a/src/main.ts b/src/main.ts index 1be88103..e32db1e3 100644 --- a/src/main.ts +++ b/src/main.ts @@ -18,12 +18,14 @@ import * as recorder from './common/recorder-h5'; import ImageResize from 'quill-image-resize-mp'; import Quill from 'quill'; import { patchH5Navigation } from '@/sheep/router/h5-navigation'; +import { initH5HostShell } from '@/sheep/platform/h5-shell'; // 以下组件用于兼容部分手机聊天边框无法输入的问题 window.Quill = Quill; window.ImageResize = { default: ImageResize }; // 调试器 -// import VConsole from 'vconsole'; -// new VConsole(); +import VConsole from 'vconsole'; +new VConsole(); +initH5HostShell(); patchH5Navigation(); // #endif // #ifndef H5 diff --git a/src/pages/home/detail.vue b/src/pages/home/detail.vue index 453b283d..c8ca9dd1 100644 --- a/src/pages/home/detail.vue +++ b/src/pages/home/detail.vue @@ -21,7 +21,7 @@ - diff --git a/src/pages/home/report.vue b/src/pages/home/report.vue index 2a1f1695..fe215d58 100644 --- a/src/pages/home/report.vue +++ b/src/pages/home/report.vue @@ -6,7 +6,7 @@ - + 举报类型 diff --git a/src/pages/moments/publish.vue b/src/pages/moments/publish.vue index 495c4a9a..f909f78e 100644 --- a/src/pages/moments/publish.vue +++ b/src/pages/moments/publish.vue @@ -12,7 +12,7 @@ - + diff --git a/src/pages/profile/apply-vip-record.vue b/src/pages/profile/apply-vip-record.vue index 1e53be8b..211f177b 100644 --- a/src/pages/profile/apply-vip-record.vue +++ b/src/pages/profile/apply-vip-record.vue @@ -7,7 +7,7 @@ - diff --git a/src/pages/profile/apply-vip.vue b/src/pages/profile/apply-vip.vue index 1185438c..4f3d01ef 100644 --- a/src/pages/profile/apply-vip.vue +++ b/src/pages/profile/apply-vip.vue @@ -24,7 +24,7 @@ - + VIP diff --git a/src/pages/profile/black-list.vue b/src/pages/profile/black-list.vue index 96b79c0b..a4fff30f 100644 --- a/src/pages/profile/black-list.vue +++ b/src/pages/profile/black-list.vue @@ -8,7 +8,7 @@ - diff --git a/src/pages/profile/like.vue b/src/pages/profile/like.vue index 7308fb37..c82cde8d 100644 --- a/src/pages/profile/like.vue +++ b/src/pages/profile/like.vue @@ -14,10 +14,10 @@ - - + - diff --git a/src/pages/profile/recharge-record.vue b/src/pages/profile/recharge-record.vue index 338a3b2c..88519318 100644 --- a/src/pages/profile/recharge-record.vue +++ b/src/pages/profile/recharge-record.vue @@ -8,7 +8,7 @@ - diff --git a/src/pages/profile/recharge.vue b/src/pages/profile/recharge.vue index b7f60544..b657d072 100644 --- a/src/pages/profile/recharge.vue +++ b/src/pages/profile/recharge.vue @@ -25,7 +25,7 @@ - + VIP diff --git a/src/pages/profile/view-record.vue b/src/pages/profile/view-record.vue index 598ab3de..f6ecfb9a 100644 --- a/src/pages/profile/view-record.vue +++ b/src/pages/profile/view-record.vue @@ -10,7 +10,7 @@ - - + diff --git a/src/pages/wechat-tabbar/index.vue b/src/pages/wechat-tabbar/index.vue index a8d97e7b..89042edb 100644 --- a/src/pages/wechat-tabbar/index.vue +++ b/src/pages/wechat-tabbar/index.vue @@ -10,7 +10,7 @@ - + diff --git a/src/pages/wechat/pages/gift/gift-record.vue b/src/pages/wechat/pages/gift/gift-record.vue index 79baf53a..351edef9 100644 --- a/src/pages/wechat/pages/gift/gift-record.vue +++ b/src/pages/wechat/pages/gift/gift-record.vue @@ -7,7 +7,7 @@ - diff --git a/src/pages/wechat/pages/gift/history.vue b/src/pages/wechat/pages/gift/history.vue index 68b7d78d..07b9c1ab 100644 --- a/src/pages/wechat/pages/gift/history.vue +++ b/src/pages/wechat/pages/gift/history.vue @@ -12,7 +12,7 @@ - + diff --git a/src/pages/wechat/pages/gift/index.vue b/src/pages/wechat/pages/gift/index.vue index 9de84ca1..8608c954 100644 --- a/src/pages/wechat/pages/gift/index.vue +++ b/src/pages/wechat/pages/gift/index.vue @@ -36,7 +36,7 @@ 礼物明细 - {{ v.title }} diff --git a/src/pages/wechat/pages/withraw-record.vue b/src/pages/wechat/pages/withraw-record.vue index d96d5acd..9e529643 100644 --- a/src/pages/wechat/pages/withraw-record.vue +++ b/src/pages/wechat/pages/withraw-record.vue @@ -7,7 +7,7 @@ - diff --git a/src/sheep/components/scroll-list/scroll-list.vue b/src/sheep/components/scroll-list/scroll-list.vue index a9afd5ca..c5734d1f 100644 --- a/src/sheep/components/scroll-list/scroll-list.vue +++ b/src/sheep/components/scroll-list/scroll-list.vue @@ -1,73 +1,60 @@ diff --git a/src/sheep/platform/h5-shell.js b/src/sheep/platform/h5-shell.js new file mode 100644 index 00000000..fc82537e --- /dev/null +++ b/src/sheep/platform/h5-shell.js @@ -0,0 +1,175 @@ +const H5_STATUS_BAR_STORAGE_KEY = '__friendship_h5_status_bar_height__'; +const H5_STATUS_BAR_QUERY_KEYS = ['statusBarHeight', 'safeTop', 'safeAreaTop', 'appStatusBarHeight']; +const H5_MIN_STATUS_BAR_HEIGHT = 22; + +function normalizeStatusBarHeight(value) { + if (value === undefined || value === null || value === '') { + return null; + } + const normalizedValue = typeof value === 'string' ? value.replace(/px$/i, '').trim() : value; + const height = Number.parseFloat(normalizedValue); + if (!Number.isFinite(height)) { + return null; + } + return Math.max(0, Math.min(height, 200)); +} + +function parseMessageData(data) { + if (!data) { + return null; + } + if (typeof data === 'string') { + try { + return JSON.parse(data); + } catch (error) { + return null; + } + } + return data; +} + +function readStatusBarHeightFromQuery() { + const searchParamsList = []; + searchParamsList.push(new URLSearchParams(window.location.search)); + const hashQuery = window.location.hash.includes('?') ? window.location.hash.split('?')[1] : ''; + if (hashQuery) { + searchParamsList.push(new URLSearchParams(hashQuery)); + } + + for (const params of searchParamsList) { + for (const key of H5_STATUS_BAR_QUERY_KEYS) { + const height = normalizeStatusBarHeight(params.get(key)); + if (height !== null) { + return height; + } + } + } + + return null; +} + +function readStatusBarHeightFromWindow() { + const candidates = [ + window.__APP_STATUS_BAR_HEIGHT__, + window.__UNI_STATUS_BAR_HEIGHT__, + window.__APP_SHELL_CONFIG__?.statusBarHeight, + window.__UNI_WEBVIEW_CONFIG__?.statusBarHeight, + ]; + for (const candidate of candidates) { + const height = normalizeStatusBarHeight(candidate); + if (height !== null) { + return height; + } + } + return null; +} + +function readStatusBarHeightFromStorage() { + try { + return normalizeStatusBarHeight(window.localStorage.getItem(H5_STATUS_BAR_STORAGE_KEY)); + } catch (error) { + return null; + } +} + +function readNativeStatusBarHeight() { + if (typeof window === 'undefined') { + return 0; + } + const rootStyle = window.getComputedStyle(document.documentElement); + return normalizeStatusBarHeight(rootStyle.getPropertyValue('--native-status-bar-height')) ?? 0; +} + +function ensureMinShellStatusBarHeight(height) { + if (height === null || height <= 0) { + return 0; + } + return Math.max(height, H5_MIN_STATUS_BAR_HEIGHT); +} + +export function getH5HostStatusBarHeight() { + if (typeof window === 'undefined') { + return 0; + } + return ensureMinShellStatusBarHeight( + readStatusBarHeightFromQuery() ?? + readStatusBarHeightFromWindow() ?? + readStatusBarHeightFromStorage() ?? + 0, + ); +} + +export function applyH5HostStatusBarHeight(height) { + if (typeof window === 'undefined') { + return 0; + } + + const safeTop = ensureMinShellStatusBarHeight(normalizeStatusBarHeight(height)); + const nativeSafeTop = readNativeStatusBarHeight(); + const finalSafeTop = Math.max(nativeSafeTop, safeTop); + const safeTopValue = `${safeTop}px`; + const finalSafeTopValue = `${finalSafeTop}px`; + const rootStyle = document.documentElement.style; + const bodyStyle = document.body?.style; + + rootStyle.setProperty('--app-shell-status-bar-height', safeTopValue); + rootStyle.setProperty('--status-bar-height', finalSafeTopValue); + bodyStyle?.setProperty('--app-shell-status-bar-height', safeTopValue); + bodyStyle?.setProperty('--status-bar-height', finalSafeTopValue); + + window.__APP_STATUS_BAR_HEIGHT__ = safeTop; + + try { + window.localStorage.setItem(H5_STATUS_BAR_STORAGE_KEY, String(safeTop)); + } catch (error) { + // ignore + } + + window.dispatchEvent( + new CustomEvent('app-shell-status-bar-change', { + detail: { height: finalSafeTop, appHeight: safeTop, nativeHeight: nativeSafeTop }, + }), + ); + + return finalSafeTop; +} + +function resolveMessageStatusBarHeight(message) { + const data = parseMessageData(message?.data); + if (!data) { + return null; + } + + return normalizeStatusBarHeight( + data.statusBarHeight ?? + data.safeTop ?? + data.safeAreaTop ?? + data.payload?.statusBarHeight ?? + data.payload?.safeTop, + ); +} + +export function initH5HostShell() { + if (typeof window === 'undefined') { + return 0; + } + + const safeTop = applyH5HostStatusBarHeight(getH5HostStatusBarHeight()); + if (window.__FRIENDSHIP_H5_SHELL_READY__) { + return safeTop; + } + + window.__FRIENDSHIP_H5_SHELL_READY__ = true; + window.setAppShellStatusBarHeight = (nextHeight) => applyH5HostStatusBarHeight(nextHeight); + window.addEventListener('message', (message) => { + const nextHeight = resolveMessageStatusBarHeight(message); + if (nextHeight !== null) { + applyH5HostStatusBarHeight(nextHeight); + } + }); + window.addEventListener('load', () => { + applyH5HostStatusBarHeight(getH5HostStatusBarHeight()); + }); + + return safeTop; +} diff --git a/src/sheep/platform/index.js b/src/sheep/platform/index.js index c9d6d7bd..9931085c 100644 --- a/src/sheep/platform/index.js +++ b/src/sheep/platform/index.js @@ -12,6 +12,7 @@ import { isEmpty } from 'lodash-es'; // #ifdef H5 import { isWxBrowser } from '@/sheep/helper/utils'; +import { getH5HostStatusBarHeight } from './h5-shell'; // #endif import wechat from './provider/wechat/index.js'; import apple from './provider/apple'; @@ -19,6 +20,12 @@ import share from './share'; import Pay from './pay'; const device = uni.getWindowInfo(); +// #ifdef H5 +const h5StatusBarHeight = getH5HostStatusBarHeight(); +if (h5StatusBarHeight > 0) { + device.statusBarHeight = h5StatusBarHeight; +} +// #endif const os = uni.getDeviceInfo().platform; diff --git a/src/sheep/ui/su-status-bar/su-status-bar.vue b/src/sheep/ui/su-status-bar/su-status-bar.vue index 9af07f93..d7a3a991 100644 --- a/src/sheep/ui/su-status-bar/su-status-bar.vue +++ b/src/sheep/ui/su-status-bar/su-status-bar.vue @@ -6,7 +6,7 @@