211 lines
5.0 KiB
Vue
211 lines
5.0 KiB
Vue
<template>
|
||
<view class="navbar">
|
||
<!-- 状态栏占位 -->
|
||
<view
|
||
v-if="safeAreaInsetTop"
|
||
class="status-bar"
|
||
:style="{ height: statusBarHeight + 'px', backgroundColor: bgColor }"
|
||
></view>
|
||
|
||
<!-- 导航栏主体 -->
|
||
<view
|
||
class="navbar-content"
|
||
:class="[contentClass, fixed ? 'navbar-fixed' : '', bordered ? 'navbar-border' : '']"
|
||
:style="{
|
||
backgroundColor: bgColor,
|
||
height: navHeight + 'px',
|
||
top: fixed ? (safeAreaInsetTop ? statusBarHeight : 0) + 'px' : '0',
|
||
}"
|
||
>
|
||
<!-- 左侧区域 -->
|
||
<view class="navbar-left" @click="handleClickLeft">
|
||
<view v-if="leftArrow" class="back-icon">
|
||
<view class="i-carbon-chevron-left text-[40rpx] text-[#333] font-semibold" />
|
||
</view>
|
||
<slot name="left"></slot>
|
||
</view>
|
||
|
||
<!-- 中间标题区域 -->
|
||
<view class="navbar-title">
|
||
<slot name="title">
|
||
<text class="title-text">{{ title }}</text>
|
||
</slot>
|
||
</view>
|
||
|
||
<!-- 右侧区域 -->
|
||
<view class="navbar-right">
|
||
<slot name="right"></slot>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 占位元素 -->
|
||
<view
|
||
v-if="placeholder && fixed"
|
||
:style="{
|
||
height: `${navHeight}px`,
|
||
backgroundColor: bgColor,
|
||
}"
|
||
></view>
|
||
<slot name="background"></slot>
|
||
</view>
|
||
</template>
|
||
|
||
<script lang="ts" setup>
|
||
import { getDeviceInfo, getWindowInfo } from '@/utils/tools'
|
||
import { computed } from 'vue'
|
||
|
||
defineProps({
|
||
title: {
|
||
type: String,
|
||
default: '',
|
||
},
|
||
leftArrow: {
|
||
type: Boolean,
|
||
default: false,
|
||
},
|
||
fixed: {
|
||
type: Boolean,
|
||
default: false,
|
||
},
|
||
placeholder: {
|
||
type: Boolean,
|
||
default: false,
|
||
},
|
||
bordered: {
|
||
type: Boolean,
|
||
default: true,
|
||
},
|
||
safeAreaInsetTop: {
|
||
type: Boolean,
|
||
default: true,
|
||
},
|
||
bgColor: {
|
||
type: String,
|
||
default: '#ffffff',
|
||
},
|
||
contentClass: {
|
||
type: String,
|
||
default: 'justify-between',
|
||
},
|
||
})
|
||
|
||
const emit = defineEmits(['clickLeft'])
|
||
|
||
// 获取系统信息
|
||
const systemInfo = getWindowInfo()
|
||
const deviceInfo = getDeviceInfo()
|
||
|
||
const statusBarHeight = systemInfo.statusBarHeight || 0
|
||
|
||
// 动态计算导航栏高度
|
||
const navHeight = computed(() => {
|
||
// 获取屏幕信息
|
||
const { screenWidth } = systemInfo
|
||
const { platform } = deviceInfo
|
||
|
||
// 将px转换为rpx的比例
|
||
const ratio = 750 / screenWidth
|
||
|
||
// 根据平台设置不同的导航栏高度
|
||
if (platform === 'ios') {
|
||
return 88 / ratio // iOS 一般是 44pt,转换为px
|
||
} else if (platform === 'android') {
|
||
return 96 / ratio // Android 一般是 48dp,转换为px
|
||
} else {
|
||
return 88 / ratio // 默认值
|
||
}
|
||
})
|
||
|
||
const handleClickLeft = () => {
|
||
emit('clickLeft')
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
.navbar {
|
||
width: 100%;
|
||
}
|
||
|
||
.status-bar {
|
||
width: 100%;
|
||
background-color: inherit;
|
||
}
|
||
|
||
.navbar-content {
|
||
box-sizing: border-box;
|
||
display: flex;
|
||
align-items: center;
|
||
width: 100%;
|
||
/* justify-content: space-between; */
|
||
padding: 0 16rpx;
|
||
background-color: #fff;
|
||
}
|
||
|
||
.navbar-fixed {
|
||
position: fixed;
|
||
left: 0;
|
||
z-index: 999;
|
||
width: 100%;
|
||
}
|
||
|
||
.navbar-border {
|
||
border-bottom: 1rpx solid #eee;
|
||
}
|
||
|
||
.navbar-left {
|
||
display: flex;
|
||
align-items: center;
|
||
min-width: 100rpx;
|
||
height: 100%;
|
||
}
|
||
|
||
.back-icon {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
height: 100%;
|
||
}
|
||
|
||
.navbar-title {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
height: 100%;
|
||
overflow: hidden;
|
||
/* flex: 1; */
|
||
text-align: center;
|
||
}
|
||
|
||
.title-text {
|
||
overflow: hidden;
|
||
font-size: 34rpx;
|
||
font-weight: 500;
|
||
color: #333;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.navbar-right {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: flex-end;
|
||
min-width: 52rpx;
|
||
height: 100%;
|
||
}
|
||
|
||
@font-face {
|
||
font-family: 'iconfont';
|
||
src: url('data:font/woff2;charset=utf-8;base64,d09GMgABAAAAAAKYAAsAAAAABlAAAAJMAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHFQGYACCcApcdgE2AiQDCAsGAAQgBYRnBzYbmQXIHpIkBQQKkYCABBEPz2/t/XN3twEbowBkQTxQEQ1RKaKSxEOi0agkJKF5Qvj/f037IFKwlZ2dWU2tJu0EhPwHkBwgOVAclKcvAQpI/v/fz/08XECy+YBymmPQiwIcSmhAY4uSFcgJ+IaxC1zCYwLtRjWSnZ2rGgQWBowLxCPrVBBYllQqNTQ0VISaBXEHtTRNUwW4jb4f/xYEC0kqMzDx6CGrQuKXxKc6Zf7POYQgQHs5kIwjYwEoxK3G/DpRwbi0dlNwKKjAL4lf6vw/R2zVWvTPIwuiCnp2wCRUZ3yJX5pJFVDfByyAFR2AblMAX/OR3t7+zOJi8GyyfzC1uQXLZvtnk/0zyfTy+PvH0/Xp5OzR98/H797/+/fDu3d/3739+/fd+/+nmxvLc5vrS+sry2vz84tLs9Mzc4vzs9NTM/Ozc1OzM3MzU/Mz0wvTU4vTk0tTE8uTEyuT4yv/G0E3XUxv7wwNbu/s9G8fbO9v7+3sb+3ubW4dbO4dbO3vbu4dbO3JzqPFtRE4gEGAX0NBkL+hpCZALkEp5FKUQqE0NHlXJIGrDNAOcEQBCHU+kXT5QNblC7kEv1EK9Y9SB/8o7YYu2m0YXrJLouNIjQJhH+QbVkVZrUQ+YuqzUJdzxPMHhdIj0+hg4o0D8ogj5r5bSoQUxjADz+A8hBDQFEYwh3mommXTul7Vm5ZtqAqJHIdoKCDYDyQ3mCqUG1YKn5+C0s0yiJ/qKVAQedKAhg6Y3mEHJBQaWKnvLVMiiEIxGAY8Aw6HIAhAJmEIzIIOUjLTTAB1taL1QvNq+fYN7QDjcc2okeioaOmy5LFXt3QAAAAA')
|
||
format('woff2');
|
||
}
|
||
|
||
.back-text {
|
||
font-family: 'iconfont' !important;
|
||
font-size: 48rpx;
|
||
font-style: normal;
|
||
-webkit-font-smoothing: antialiased;
|
||
-moz-osx-font-smoothing: grayscale;
|
||
color: #333;
|
||
}
|
||
</style>
|