UniApp微信小程序自定义导航栏
在UniApp开发微信小程序时,页面左上角默认有一个返回按钮(在导航栏左侧),但有时我们需要自定义这个按钮的样式和功能,同时保持与导航栏中间的标题和右侧胶囊按钮(药丸屏)的高度一致。
微信小程序的导航栏分为三部分:左侧(返回和主页)、中间(标题)、右侧(胶囊按钮)。自定义左侧按钮时,我们需要注意以下几点:
-
微信小程序的导航栏是原生的,我们无法直接修改原生返回按钮的样式,因此常见的做法是隐藏原生导航栏,使用自定义导航栏。
-
自定义导航栏需要计算导航栏的高度,尤其是要考虑到不同机型的适配(如iPhone的刘海屏、状态栏高度等)。
-
右侧的胶囊按钮(药丸屏)的尺寸和位置是固定的,我们可以通过微信提供的API获取其位置信息,以便让自定义按钮与胶囊按钮对齐。
具体步骤如下:
1. 隐藏原生导航栏
在pages.json
中,设置页面或全局的导航栏为自定义:
json
{
"pages": [
{
"path": "pages/index/index",
"style": {
"navigationStyle": "custom" // 使用自定义导航栏
}
}
],
// 或者全局设置
"globalStyle": {
"navigationStyle": "custom"
}
}
2. 在页面中编写自定义导航栏
在页面的vue文件中,我们需要自己编写一个导航栏组件,通常放在页面顶部。
3. 获取状态栏高度和胶囊按钮位置
我们可以使用uni.getSystemInfoSync()
来获取状态栏高度,以及使用uni.getMenuButtonBoundingClientRect()
来获取胶囊按钮的位置信息。
示例代码:
javascript
const systemInfo = uni.getSystemInfoSync();
const menuButtonInfo = uni.getMenuButtonBoundingClientRect();
// 状态栏高度(手机顶部状态栏区域的高度)
const statusBarHeight = systemInfo.statusBarHeight;
// 胶囊按钮距离顶部的距离(通常比状态栏高度多一点点,具体以获取到的为准)
const menuButtonTop = menuButtonInfo.top;
// 导航栏高度 = 胶囊按钮高度 + (胶囊按钮上边距 - 状态栏高度) * 2
// 因为胶囊按钮上下有间隙,所以导航栏高度可以这样计算:
const navBarHeight = (menuButtonTop - statusBarHeight) * 2 + menuButtonInfo.height;
// 整个自定义导航栏的高度 = 状态栏高度 + 导航栏高度
const customBarHeight = statusBarHeight + navBarHeight;
4. 布局自定义导航栏
在模板中,我们使用计算得到的高度来设置导航栏的样式,确保高度与原生导航栏一致。
左侧按钮的位置需要与胶囊按钮对齐(垂直方向),因此我们可以将左侧按钮的顶部设置为menuButtonTop
(胶囊按钮的顶部位置),然后通过调整上边距或使用绝对定位来实现。
示例模板结构:
html
<template>
<view>
<!-- 自定义导航栏 -->
<view class="custom-nav" :style="{ height: customBarHeight + 'px', paddingTop: statusBarHeight + 'px' }">
<!-- 左侧按钮 -->
<view class="left-btn" :style="{ top: menuButtonTop + 'px' }" @click="goHome">
<!-- 这里可以放置自定义图标或文字 -->
<image src="/static/home.png" mode="aspectFit"></image>
</view>
<!-- 中间标题 -->
<view class="title" :style="{ height: navBarHeight + 'px', lineHeight: navBarHeight + 'px' }">
标题
</view>
<!-- 右侧通常不需要添加内容,因为胶囊按钮是原生的,但我们也可以自定义右侧内容,但要注意与胶囊按钮的位置不重叠 -->
</view>
<!-- 页面内容,需要设置一个上边距,避免被导航栏覆盖 -->
<view :style="{ marginTop: customBarHeight + 'px' }">
... 页面内容 ...
</view>
</view>
</template>
样式示例(使用scss):
css
.custom-nav {
position: fixed;
top: 0;
left: 0;
width: 100%;
box-sizing: border-box;
background-color: #ffffff;
z-index: 999;
.left-btn {
position: absolute;
left: 10px;
height: 30px; // 胶囊按钮的高度可以通过menuButtonInfo.height获取,这里假设30px
display: flex;
align-items: center;
justify-content: center;
// 通过top定位垂直位置,与胶囊按钮对齐
image {
width: 20px;
height: 20px;
}
}
.title {
text-align: center;
font-size: 16px;
}
}
5. 自定义按钮的功能
在goHome
方法中,我们可以实现跳转到首页的功能:
javascript
methods: {
goHome() {
uni.reLaunch({
url: '/pages/index/index'
});
}
}
注意事项:
-
由于自定义导航栏是固定在顶部的,页面内容需要设置一个上边距(等于自定义导航栏的高度),避免内容被导航栏覆盖。
-
不同机型的胶囊按钮位置可能略有差异,所以一定要动态获取胶囊按钮的位置信息。
-
在微信开发者工具中,胶囊按钮的位置信息可能与真机有差异,建议在真机测试。
通过以上步骤,我们就可以自定义一个与中间标题和右侧胶囊按钮高度一致的左侧按钮,并实现自定义功能。
在 UniApp 开发微信小程序时,要自定义左上角返回按钮并保持与标题栏、右侧胶囊按钮高度对齐,需使用自定义导航栏方案。以下是完整实现步骤:
核心思路
隐藏原生导航栏,使用自定义导航栏组件
精确计算布局尺寸,匹配微信胶囊按钮位置
使用绝对定位控制自定义按钮位置
实现步骤
1. 配置全局自定义导航栏(pages.json)
javascript
{
"globalStyle": {
"navigationStyle": "custom",
"transparentTitle": "always",
"navigationBarTextStyle": "black"
}
}
2. 创建自定义导航栏组件(components/custom-navbar.vue)
javascript
<template>
<view class="custom-navbar">
<!-- 状态栏占位 -->
<view :style="{ height: statusBarHeight + 'px' }"></view>
<!-- 导航栏主体 -->
<view class="navbar-content" :style="{ height: navBarHeight + 'px' }">
<!-- 左侧自定义按钮 -->
<view
class="custom-home-btn"
:style="btnStyle"
@click="handleHomeClick">
<image src="/static/home-icon.png" class="icon" />
</view>
<!-- 标题居中 -->
<view class="title" :style="titleStyle">{{ title }}</view>
</view>
</view>
</template>
<script>
export default {
props: {
title: String
},
data() {
return {
statusBarHeight: 20, // 默认值
navBarHeight: 44, // 默认值
menuButtonInfo: null
};
},
computed: {
// 按钮样式计算(核心)
btnStyle() {
if (!this.menuButtonInfo) return {};
return {
width: '30px',
height: this.menuButtonInfo.height + 'px',
top: this.menuButtonInfo.top + 'px'
};
},
// 标题位置适配
titleStyle() {
return {
height: this.menuButtonInfo.height + 'px',
lineHeight: this.menuButtonInfo.height + 'px'
};
}
},
mounted() {
this.initSystemInfo();
},
methods: {
initSystemInfo() {
const systemInfo = uni.getSystemInfoSync();
this.statusBarHeight = systemInfo.statusBarHeight;
// 获取微信胶囊按钮位置
const menuButtonInfo = uni.getMenuButtonBoundingClientRect();
this.menuButtonInfo = menuButtonInfo;
// 计算导航栏高度 = 胶囊按钮高度 + (胶囊按钮上间距 - 状态栏高度) * 2
this.navBarHeight = menuButtonInfo.height +
(menuButtonInfo.top - systemInfo.statusBarHeight) * 2;
},
handleHomeClick() {
// 自定义按钮功能(示例:返回首页)
uni.reLaunch({ url: '/pages/index/index' });
}
}
};
</script>
<style scoped>
.custom-navbar {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 9999;
background: white;
}
.navbar-content {
position: relative;
display: flex;
justify-content: center;
align-items: center;
}
.custom-home-btn {
position: absolute;
left: 15px;
display: flex;
align-items: center;
justify-content: center;
z-index: 10;
}
.icon {
width: 22px;
height: 22px;
}
.title {
font-size: 16px;
font-weight: 500;
max-width: 60%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
</style>
3. 在页面中使用自定义导航栏
javascript
<template>
<view>
<!-- 引入自定义导航栏 -->
<custom-navbar title="我的页面" />
<!-- 页面内容 (需要设置顶部内边距) -->
<view :style="{ paddingTop: navBarTotalHeight + 'px' }">
<!-- 页面内容... -->
</view>
</view>
</template>
<script>
import customNavbar from '@/components/custom-navbar.vue'
export default {
components: { customNavbar },
data() {
return {
// 计算:状态栏高度 + 导航栏高度
navBarTotalHeight: 64 // 默认值
}
},
onLoad() {
this.calcNavbarHeight()
},
methods: {
calcNavbarHeight() {
const systemInfo = uni.getSystemInfoSync()
const menuButtonInfo = uni.getMenuButtonBoundingClientRect()
this.navBarTotalHeight = systemInfo.statusBarHeight +
menuButtonInfo.height +
(menuButtonInfo.top - systemInfo.statusBarHeight) * 2
}
}
}
</script>
关键点说明
胶囊按钮对齐原理:
- 使用 uni.getMenuButtonBoundingClientRect() 获取胶囊按钮的精确位置信息
- 通过公式计算导航栏高度:胶囊高度 + (胶囊上间距 - 状态栏高度) × 2
- 按钮垂直定位使用胶囊按钮的 top 值
响应式处理:
- 不同机型适配(iPhone 刘海屏、Android 等)
- 小程序右上角胶囊按钮位置是固定的
- 页面滚动时导航栏保持固定定位
样式定制:
- 替换 /static/home-icon.png 为自定义图标
- 调整 left 值控制水平位置
- 修改按钮的宽高和图标尺寸
注意事项
- **真机测试:**微信开发者工具中的胶囊位置与真机可能有差异
- **iOS 安全区域:**iPhone X 及以上机型需要处理底部安全区域
- **页面滚动:**页面内容需要设置 padding-top 避免内容被导航栏遮挡
- **组件复用:**建议封装成全局组件减少重复代码
通过此方案,自定义按钮可以实现:
- 与原生胶囊按钮完美对齐 ✅
- 支持自定义图标和点击事件 ✅
- 完美适配不同机型 ✅
- 保持原生导航栏流畅体验 ✅