uni-app(uni-app-x)自定义导航栏组件 uni-nav-bar 完全指南:安全区适配、三区布局与 slot 扩展
【免费下载链接】uni-appA cross-platform framework using Vue.js项目地址: https://gitcode.com/gh_mirrors/un/uni-app
uni-nav-bar 是 uni-app / uni-app-x 官方提供的轻量级自定义导航栏组件,用于在页面关闭原生导航栏(navigationStyle: "custom")后,用纯声明式的方式重建顶部导航区域。本文将围绕该组件在仓库中的官方文档(readme.md)与真实源码(uni-nav-bar.vue)展开,带你掌握安全区适配原理、left/mid/right 三区布局、返回箭头、标题与前景色控制,以及如何用 slot 和外部 class 完成任意自定义。
一、组件定位:接管被关闭的原生导航栏
在 uni-app 中,页面默认自带原生导航栏。当页面需要沉浸式设计、自定义标题栏样式或与内容区域一体化时,通常会在pages.json中把该页面的导航样式改为自定义:
{ "pages": [ { "path": "pages/index/index", "style": { "navigationStyle": "custom" } } ] }配置"navigationStyle": "custom"之后,原生导航栏不再渲染,页面顶部完全交由开发者自己控制。此时即可引入本组件替代原生导航栏。仓库自身的演示工程在 src/pages.json 中即为navbar-lite/navbar-lite页面配置了"navigationStyle": "custom",并在 navbar-lite.uvue 中直接使用了组件:
<uni-nav-bar :title="title" :is-left="isLeft" :navigationBarTextStyle="navigationBarTextColor"></uni-nav-bar>从 package.json 的uni_modules.platforms声明可以看出,该组件的 uni-app-x 版本支持 Android、iOS、HarmonyOS、Web(safari/chrome)以及微信小程序端,属于纯跨端组件,无需额外原生依赖。
二、安全区适配与尺寸约定
组件在模板根部对顶部安全区做了自动适配(见 uni-nav-bar.vue):
<view style="flex-direction: row;padding-top: var(--status-bar-height);box-sizing: content-box;align-items: center;position: relative;">核心要点:
- 通过
padding-top: var(--status-bar-height)让出顶部状态栏(刘海屏/挖孔屏)的高度,状态栏区域不再遮挡内容; - 外层使用
box-sizing: content-box,确保内层内容高度不受 padding 影响; - 除去状态栏高度后,组件主体高度固定为44px,这也是 iOS 原生导航栏的标准高度,视觉上与系统保持一致;
- 组件左右两边默认各让出 6px 边距(见样式区
.uni-left-class-buildin { margin-left: 6px }与.uni-right-class-buildin { margin-right: 6px }),让按钮不至于贴边。
需要自定义左右间距时,通过left-class与right-class传入自定义样式类覆盖即可,同时组件底部也预留了--uni-safe-area-inset-bottom一类的安全区变量供页面内容使用(参见 navbar-lite.uvue 的用法)。
三、left / mid / right 三区布局
组件内部结构分为三个区域(见 uni-nav-bar.vue):
| 区域 | 默认行为 | 默认宽度 | 自定义方式 |
|---|---|---|---|
| left | 显示返回箭头(44×44px 点击区) | 44px(含 6px 左边距) | slot name="left"替代;left-class修饰样式;hideDefaultBack隐藏箭头 |
| mid | 显示title属性设置的标题 | 屏幕宽度 − 左右边距 − left 宽 − right 宽(样式实现为left: 52px; right: 52px,即 6+44) | slot name="mid"替代;mid-class修饰样式 |
| right | 默认不显示内容 | 44px(含 6px 右边距) | slot name="right"填充内容;right-class修饰样式 |
从源码可以确认,mid 区域的绝对定位区间为left: 52px; right: 52px(注释中明确 52 = padding 6 + 44),因此标题默认居中于「两侧各 52px」的安全区间内。flatten属性用于降低该节点的层级负担,保证绝对定位内容正确覆盖。
3.1 left 区域:返回箭头与点击区放大
默认返回箭头并非使用图片,而是由两个 view 通过 CSS 旋转拼出的箭头(uni-nav-bar.vue):
<view v-if="!hideDefaultBack && slots['left']==null" style="width: 44px;height: 44px;justify-content: center;align-items: center;" @click="back"> <view style="width: 12px;height: 12px;transform: rotate(45deg); border-left: 2px solid; border-bottom: 2px solid;" :style="{borderLeftColor:foreColor,borderBottomColor:foreColor}"></view> </view>- 内层箭头大小为 12×12px、由左边框与下边框旋转 45° 组成;
- 外层再套一层 44×44px 的透明容器以扩大点击区域,符合移动端最小触控尺寸规范;
- 点击调用
back(),其实现为uni.navigateBack({})(uni-nav-bar.vue),即返回上一页; - 传入
hideDefaultBack可隐藏该箭头,此时leftslot 若存在则会替换显示。
3.2 mid 区域:标题与居中/居左切换
mid 区域在slots['mid']为空时渲染title文本,颜色由foreColor控制;传入slot name="mid"后 title 属性不再生效(readme 明确「如果传入 mid slot,则不生效」)。
组件还额外提供了isLeft布尔属性:为true时标题在 mid 区域内左对齐(justify-content: flex-start),否则居中(justify-content: center)。仓库示例页面 navbar-lite.uvue 正是通过点击切换isLeft来演示「标题居中 / 居左」两种形态。
3.3 right 区域:默认空白,slot 自由填充
right 区域默认不渲染任何内容,仅保留 44px 宽度占位,通过slot name="right"放入自定义按钮、文字或图标。
四、属性详解
完整属性定义见组件脚本区(uni-nav-bar.vue):
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
hideDefaultBack | Boolean | false | 是否隐藏默认返回箭头 |
title | String | "" | 标题文本;传入midslot 后不生效 |
navigationBarTextStyle | String | "" | 返回箭头与标题的前景色,可选white/black(也支持#fff/#ffffff/#000/#000000等十六进制写法);不传时在非 MP 平台自动读取页面pageStyle的navigationBarTextStyle |
leftClass | String | "" | left 区域外部样式类 |
midClass | String | "" | mid 区域外部样式类 |
rightClass | String | "" | right 区域外部样式类 |
isLeft | Boolean | false | 标题是否左对齐(false 为居中) |
4.1 navigationBarTextStyle 的前景色获取逻辑
源码中foreColor是一个computed,且存在平台差异(uni-nav-bar.vue):
- 非 MP 平台:当外部未传入
navigationBarTextStyle(为空字符串)时,通过getCurrentInstance()?.proxy?.$page?.getPageStyle()["navigationBarTextStyle"]自动获取页面pageStyle的默认值;只有显式传入时才以传入值为准。 - MP(小程序)平台:小程序端无法获取
pageStyle,因此foreColor直接等于传入的navigationBarTextStyle,必须显式传入前景色,否则返回箭头与标题会使用默认色。
这意味着在微信小程序等 MP 端使用本组件时,请务必显式传入navigationBarTextStyle,避免出现颜色与页面风格不一致的情况。
4.2 动态切换前景色示例
仓库演示页 navbar-lite.uvue 展示了通过uni.setNavigationBarColor动态修改导航栏背景、再同步组件前景色的完整写法:
function setNavigationBarColor1() { uni.setNavigationBarColor({ frontColor: '#ffffff', backgroundColor: '#0000', success: () => { navigationBarTextColor.value = '#fff' }, fail: () => { /* ... */ }, complete: () => { /* ... */ } }) }页面中的navigationBarTextColor为响应式变量,绑定到组件的:navigationBarTextStyle上,前景色随之联动更新。
五、插槽与外部类:三种自定义路径
组件支持两种自定义机制,对应 readme 中的描述:
Slot 替换(内容级自定义):
slot name="left":整体替换 left 区域内容(替换后默认返回箭头不再渲染);slot name="mid":替换 mid 区域内容(title属性失效);slot name="right":填充 right 区域自定义内容。
externalClasses(样式级自定义):组件通过
defineOptions声明了externalClasses: ['left-class','mid-class','right-class'](uni-nav-bar.vue),在页面使用组件时给left-class/mid-class/right-class传入自定义 class,即可在不改组件源码的情况下覆盖三区样式——例如修改左右边距、调整标题字号、给 right 区增加底色等。
三区默认样式可在组件
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考