import React, { useMemo } from 'react' import Taro from '@tarojs/taro' import { View, Text } from '@tarojs/components' import styles from './index.module.scss' /** * 运行时导航栏尺寸(px,需内联样式动态应用)。 */ export interface NavBarMetrics { /** 状态栏高度(px) */ statusBarHeight: number /** 导航内容区高度(px),即胶囊按钮所在行的高度 */ navContentHeight: number /** 状态栏 + 内容区总高度(px),页面顶部留白直接使用该值 */ totalHeight: number } /** * 获取自定义导航栏运行时尺寸。 * *
计算规则:内容区高度 = (胶囊顶部 - 状态栏高度) × 2 + 胶囊高度, * 保证标题与右上角胶囊按钮垂直居中对齐;非微信端(H5 预览等) * 胶囊 API 不可用时降级为 statusBar 20px + content 44px 的通用值。
*/ export function useNavBarMetrics(): NavBarMetrics { return useMemo(() => { let statusBarHeight = 20 let navContentHeight = 44 try { const sysInfo = Taro.getSystemInfoSync() statusBarHeight = sysInfo.statusBarHeight || 20 if (typeof Taro.getMenuButtonBoundingClientRect === 'function') { const rect = Taro.getMenuButtonBoundingClientRect() if (rect && rect.top > 0 && rect.height > 0) { navContentHeight = (rect.top - statusBarHeight) * 2 + rect.height } } } catch (err) { console.warn('[CustomNavBar] 获取系统信息失败,使用默认导航高度:', err) } return { statusBarHeight, navContentHeight, totalHeight: statusBarHeight + navContentHeight } }, []) } interface CustomNavBarProps { /** 导航栏标题 */ title: string /** 页面滚动后显示底色与阴影(透明 → 主题色),由页面根据滚动位置传入 */ solid?: boolean /** 是否显示返回按钮(非 tabBar 子页传入 true);默认 false */ showBack?: boolean } /** * 自定义导航栏(沉浸式)。 * *为什么需要自定义:原生导航栏与页面渐变背景之间存在硬分界线, * 无法实现"渐变从状态栏一气呵成"的沉浸式视觉效果;自定义导航栏透明悬浮于 * 页面渐变之上,滚动后切换为主题色底 + 阴影,保证标题可读性。
* *使用约定:页面需设置 {@code navigationStyle: 'custom'}, * 并通过 {@link useNavBarMetrics} 将页面顶部内容让出导航高度, * 防止标题遮挡内容。子页面(非 tabBar 页)可开启 {@code showBack} 显示返回按钮。
* * @author haisen */ const CustomNavBar: React.FC