Skip to content

自定义导航栏

微信小程序使用 navigationStyle: "custom" 时,需自行处理状态栏高度、胶囊避让和页面布局。

核心公式

微信小程序导航栏高度(uni-ui 官方):

导航栏高度 = 胶囊高度 + (胶囊top - 状态栏高度) × 2
总高度 = 状态栏高度 + 导航栏高度

H5 / App 无胶囊,navBarHeight = 44

平台差异

平台状态栏高度胶囊按钮处理方式
微信小程序动态获取(20-44px)需要避让胶囊
H50不需要避让
App动态获取不需要避让

使用 useNavbar

项目封装了 useNavbar composable 统一处理导航栏计算:

ts
import { useNavbar } from "@/composables/useNavbar"

// 基本用法
const { statusBarHeight, totalHeight, contentPaddingTop } = useNavbar()

// TabBar 页面
const navbar = useNavbar({ hasTabbar: true })

返回值

属性类型说明
statusBarHeightRef<number>状态栏高度
navBarHeightnumber导航栏内容高度
totalHeightComputedRef<number>导航栏总高度
contentPaddingTopComputedRef<string>页面 paddingTop
safeAreaBottomRef<number>安全区域底部高度
menuButtonRef<MenuButtonRect | null>胶囊按钮信息
menuButtonRightGapComputedRef<number>胶囊按钮右侧距离
menuButtonLeftComputedRef<number>胶囊按钮左侧距离
contentWidthComputedRef<number>内容区域可用宽度

使用 custom-navbar 组件

页面直接使用 <custom-navbar> 即可,组件内部调用 useNavbar() 处理所有高度计算。

vue
<custom-navbar title="页面标题" fixed placeholder />

Props

参数说明类型默认值
title标题文字string""
titleColor标题颜色stringvar(--color-text)
bgColor背景色stringvar(--color-bg)
iconColor图标颜色stringvar(--color-text)
showBack是否显示返回按钮booleantrue
showHome是否显示首页按钮booleanfalse
backIcon返回按钮图标名string"arrow-left"
backIconSize返回按钮图标大小string"40rpx"
fixed是否固定到顶部booleantrue
placeholderfixed 时是否自动占位booleanfalse
navBarHeight导航栏内容高度number44

Events

事件说明
back点击返回按钮时触发
home点击首页按钮时触发

Slots

插槽说明
left左侧区域(返回/首页按钮之后)
center中间区域(标题之后,标题用 #center 可替换)
right右侧区域

场景模板

TabBar 页面 + 非沉浸式

内容从导航栏下方开始,placeholder 自动占位。

vue
<template>
  <view class="page page--tabbar">
    <custom-navbar title="首页" :show-back="false" fixed placeholder />
    <view class="content">
      <!-- 页面内容 -->
    </view>
  </view>
</template>

TabBar 页面 + 沉浸式

轮播图铺到顶部,导航栏透明叠加。

vue
<template>
  <view class="page page--tabbar">
    <view class="hero" :style="{ paddingTop: `${navbar.totalHeight.value}px` }">
      <custom-navbar
        fixed :placeholder="false"
        bg-color="transparent"
        title-color="var(--color-text-inverse)"
        icon-color="var(--color-text-inverse)"
        :show-back="false"
      />
      <wd-swiper :list="swiperList" autoplay />
    </view>
    <view class="content">
      <!-- 其余内容 -->
    </view>
  </view>
</template>

<script setup>
import { useNavbar } from "@/composables/useNavbar"
const navbar = useNavbar({ hasTabbar: true })
</script>

普通页面 + 自定义导航栏

vue
<template>
  <view class="page">
    <custom-navbar title="详情" fixed placeholder />
    <view class="content">
      <!-- 页面内容 -->
    </view>
  </view>
</template>

scroll-view 固定列表

列表区域独立滚动,导航栏固定。

vue
<template>
  <view class="page">
    <custom-navbar title="列表" fixed placeholder />
    <scroll-view scroll-y :style="scrollStyle">
      <!-- 列表内容 -->
    </scroll-view>
  </view>
</template>

<script setup>
import { useNavbar } from "@/composables/useNavbar"
const navbar = useNavbar({ hasTabbar: false })
const scrollStyle = computed(() => ({
  height: `calc(100vh - ${navbar.totalHeight.value}px)`,
}))
</script>

常见坑点

坑点原因解决
内容与导航栏重叠未设 paddingTop 或 placeholder使用 placeholderpaddingTop: totalHeight
页面未超高却能滚动min-height: 100vh 未减去导航栏优先不设 min-height,让内容自然撑开
按钮与胶囊重叠未避让胶囊按钮使用 menuButtonRightGap
getMenuButtonBoundingClientRect 返回 0iOS 预览时偶发useNavbar 内置重试与降级

原则

  • 不要依赖 --status-bar-height(小程序端固定 25px)
  • 不要无脑 min-height: 100vh
  • 不要重复叠加占位(系统导航栏 + 自定义 placeholder 同时存在)
  • TabBar 页面滚动容器 bottom 需减去 TabBar + safeAreaBottom

参考资源

基于 MIT 许可发布 · 由 ❤️ 和 ☕ 驱动 · 支持作者