mi-assessment/uniapp/components/Navbar/index.vue
2026-02-21 23:42:15 +08:00

225 lines
4.2 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script setup>
/**
* 自定义导航栏组件
*
* Props:
* - title: 标题文字
* - showBack: 是否显示返回按钮
* - transparent: 是否透明背景
* - textColor: 文字颜色 (light/dark)
* - backgroundColor: 背景颜色
*
* Events:
* - back: 点击返回按钮
*
* Slots:
* - left: 左侧自定义内容
* - right: 右侧自定义内容
* - default: 中间自定义内容替代title
*/
import { computed } from 'vue'
import { useNavbar } from '../../composables/useNavbar.js'
const props = defineProps({
title: {
type: String,
default: ''
},
showBack: {
type: Boolean,
default: true
},
transparent: {
type: Boolean,
default: false
},
textColor: {
type: String,
default: 'dark',
validator: (value) => ['light', 'dark'].includes(value)
},
backgroundColor: {
type: String,
default: '#FFFFFF'
}
})
const emit = defineEmits(['back'])
const { statusBarHeight, navbarHeight, totalNavbarHeight } = useNavbar()
// 导航栏容器样式
const navbarStyle = computed(() => {
const style = {
paddingTop: `${statusBarHeight.value}px`,
height: `${totalNavbarHeight.value}rpx`
}
if (!props.transparent) {
style.backgroundColor = props.backgroundColor
}
return style
})
// 导航栏内容样式
const contentStyle = computed(() => ({
height: `${navbarHeight.value}px`
}))
// 占位元素样式
const placeholderStyle = computed(() => ({
height: `${totalNavbarHeight.value}px`
}))
// 文字颜色
const textColorValue = computed(() => {
return props.textColor === 'light' ? '#FFFFFF' : '#333333'
})
// 返回按钮颜色
const backIconColor = computed(() => {
return props.textColor === 'light' ? '#FFFFFF' : '#333333'
})
/**
* 处理返回
*/
function handleBack() {
emit('back')
const pages = getCurrentPages()
if (pages.length > 1) {
uni.navigateBack()
} else {
uni.switchTab({
url: '/pages/index/index'
})
}
}
</script>
<template>
<view class="navbar-wrapper">
<!-- 导航栏 -->
<view
class="navbar"
:class="{ 'navbar--transparent': transparent }"
:style="navbarStyle"
>
<view class="navbar__content" :style="contentStyle">
<!-- 左侧区域 -->
<view class="navbar__left">
<slot name="left">
<view
v-if="showBack"
class="navbar__back"
@click="handleBack"
>
<view class="navbar__back-icon" :style="{ borderColor: backIconColor }"></view>
</view>
</slot>
</view>
<!-- 中间区域 -->
<view class="navbar__center">
<slot>
<text
class="navbar__title"
:style="{ color: textColorValue }"
>{{ title }}</text>
</slot>
</view>
<!-- 右侧区域 -->
<view class="navbar__right">
<slot name="right"></slot>
</view>
</view>
</view>
<!-- 占位元素 -->
<view v-if="!transparent" class="navbar__placeholder" :style="placeholderStyle"></view>
</view>
</template>
<style scoped lang="scss">
.navbar-wrapper {
position: relative;
}
.navbar {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 999;
&--transparent {
background-color: transparent;
}
}
.navbar__content {
display: flex;
align-items: center;
padding: 0 24rpx;
}
.navbar__left,
.navbar__right {
width: 80rpx;
flex-shrink: 0;
}
.navbar__left {
display: flex;
align-items: center;
justify-content: flex-start;
}
.navbar__right {
display: flex;
align-items: center;
justify-content: flex-end;
}
.navbar__center {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
}
.navbar__title {
font-size: 34rpx;
font-weight: 500;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.navbar__back {
display: flex;
align-items: center;
justify-content: center;
width: 60rpx;
height: 60rpx;
}
.navbar__back-icon {
width: 20rpx;
height: 20rpx;
border-left: 4rpx solid #333;
border-bottom: 4rpx solid #333;
transform: rotate(45deg);
margin-left: 8rpx;
}
.navbar__placeholder {
width: 100%;
}
</style>