<!-- components/custom-nav-bar/custom-nav-bar.vue -->
<template>
<view class="custom-nav" :style="{ backgroundColor: bgColor }">
<!-- 状态栏占位 -->
<view class="status-bar" :style="{ height: statusBarHeight + 'px' }"></view>
<!-- 导航栏内容区 -->
<view class="nav-content" :style="navContentStyle">
<view class="nav-left" @click="onClickLeft">
<slot name="left">
<view v-if="leftIcon" class="left-icon">
<uni-icons :type="leftIcon" size="20" color="#333"></uni-icons>
</view>
</slot>
</view>
<view class="nav-center">
<slot name="center">
<text class="nav-title" :style="{ color: titleColor }">{{ title }}</text>
</slot>
</view>
<view class="nav-right">
<slot name="right">
<view v-if="rightIcon" class="right-icon" @click="onClickRight">
<uni-icons :type="rightIcon" size="20" color="#333"></uni-icons>
</view>
</slot>
</view>
</view>
</view>
<!-- 占位,防止内容被遮挡 -->
<view v-if="fixed" class="nav-placeholder" :style="placeholderStyle"></view>
</template>
<script>
export default {
name: 'CustomNavBar',
props: {
// 标题
title: {
type: String,
default: ''
},
// 标题颜色
titleColor: {
type: String,
default: '#333333'
},
// 左侧图标
leftIcon: {
type: String,
default: 'left'
},
// 右侧图标
rightIcon: {
type: String,
default: ''
},
// 背景颜色
bgColor: {
type: String,
default: '#FFFFFF'
},
// 是否固定在顶部
fixed: {
type: Boolean,
default: true
}
},
data() {
return {
statusBarHeight: 0, // 状态栏高度
navBarHeight: 44, // 导航栏高度
menuButtonInfo: null // 胶囊按钮信息
}
},
computed: {
// 导航栏内容样式
navContentStyle() {
let style = {
height: this.navBarHeight + 'px'
}
// #ifdef MP-WEIXIN
if (this.menuButtonInfo) {
style = {
...style,
height: (this.menuButtonInfo.height + 8) + 'px',
paddingTop: (this.menuButtonInfo.top - this.statusBarHeight) + 'px',
paddingRight: (this.systemInfo.windowWidth - this.menuButtonInfo.left) + 'px'
}
}
// #endif
return style
},
// 占位符样式
placeholderStyle() {
return {
height: (this.statusBarHeight + this.navBarHeight) + 'px'
}
}
},
created() {
this.initNavBar()
},
methods: {
// 初始化导航栏
initNavBar() {
// 获取系统信息
const systemInfo = uni.getSystemInfoSync()
this.systemInfo = systemInfo
this.statusBarHeight = systemInfo.statusBarHeight
// #ifdef MP-WEIXIN
// 获取胶囊按钮信息
this.menuButtonInfo = uni.getMenuButtonBoundingClientRect()
this.navBarHeight = (this.menuButtonInfo.height + 8)
// #endif
// #ifdef APP-PLUS
// 判断是否是全面屏
const isIphoneX = this.isIphoneX(systemInfo)
if (isIphoneX) {
this.navBarHeight = 48
}
// #endif
},
// 判断是否是全面屏
isIphoneX(systemInfo) {
const model = systemInfo.model.toLowerCase()
const isIphoneX = model.includes('iphone x') ||
model.includes('iphone 11') ||
model.includes('iphone 12') ||
model.includes('iphone 13') ||
model.includes('iphone 14') ||
model.includes('iphone 15')
return isIphoneX
},
// 左侧点击事件
onClickLeft() {
this.$emit('clickLeft')
},
// 右侧点击事件
onClickRight() {
this.$emit('clickRight')
}
}
}
</script>
<style lang="scss">
.custom-nav {
position: relative;
&.fixed {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 999;
}
}
.status-bar {
width: 100%;
}
.nav-content {
position: relative;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 15px;
box-sizing: border-box;
.nav-left, .nav-right {
min-width: 44px;
height: 100%;
display: flex;
align-items: center;
}
.nav-center {
flex: 1;
text-align: center;
.nav-title {
font-size: 16px;
font-weight: 500;
}
}
.left-icon, .right-icon {
display: flex;
align-items: center;
justify-content: center;
width: 44px;
height: 100%;
}
}
/* #ifdef MP-WEIXIN */
.custom-nav {
padding-right: var(--window-right, 0);
.nav-content {
.nav-left {
padding-left: 10px;
}
.nav-right {
padding-right: 10px;
}
}
}
/* #endif */
/* #ifdef APP-PLUS */
.custom-nav {
.nav-content {
padding: 0 12px;
}
}
/* #endif */
</style>
使用示例
<!-- pages/index/index.vue -->
<template>
<view class="page">
<!-- 基础用法 -->
<custom-nav-bar
title="页面标题"
@clickLeft="handleBack"
/>
<!-- 自定义样式 -->
<custom-nav-bar
title="自定义导航栏"
titleColor="#FFFFFF"
bgColor="#007AFF"
rightIcon="more"
@clickLeft="handleBack"
@clickRight="handleMore"
/>
<!-- 自定义内容 -->
<custom-nav-bar>
<template #left>
<view class="custom-left">返回</view>
</template>
<template #center>
<view class="custom-center">
<image src="/static/logo.png" mode="aspectFit" />
</view>
</template>
<template #right>
<view class="custom-right">
<button size="mini">操作</button>
</view>
</template>
</custom-nav-bar>
<!-- 页面内容 -->
<view class="content">
页面内容
</view>
</view>
</template>
<script>
export default {
methods: {
handleBack() {
uni.navigateBack({
delta: 1
})
},
handleMore() {
uni.showToast({
title: '点击了更多'
})
}
}
}
</script>
<style lang="scss">
.page {
min-height: 100vh;
background-color: #f5f5f5;
}
.content {
padding: 15px;
}
.custom-left {
font-size: 14px;
color: #333;
}
.custom-center {
height: 30px;
image {
height: 100%;
width: auto;
}
}
.custom-right {
button {
margin: 0;
}
}
</style>
组件的主要特点:
- 自适应状态栏高度
- 支持自定义标题、图标和颜色
- 支持自定义左中右三个插槽
- 适配微信小程序胶囊按钮
- 适配 iPhone 全面屏
- 支持固定顶部
使用方法:
- 将组件文件放入项目的 components 目录
- 在页面中引入并注册组件