buddhism/components/custom-navbar/custom-navbar.vue
2025-10-17 17:38:09 +08:00

233 lines
5.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.

<template>
<view>
<!-- 填充区避免内容被导航栏遮挡 -->
<view
:style="{ height: navBarHeight + 'px' }"
class="navbar-placeholder"
></view>
<!-- 自定义导航栏 -->
<view
:class="{ 'navbar-scrolled': isScrolled }"
:style="{
paddingTop: statusBarHeight + 'px',
height: navBarHeight + 'px',
backgroundColor: isScrolled ? backgroundColor : 'transparent',
}"
class="custom-navbar"
>
<view
:style="{
height: capsuleHeight + 'px',
lineHeight: capsuleHeight + 'px',
}"
class="navbar-left"
@click="handleBack"
>
<image :src="backIcon" class="back-icon" mode="aspectFit"></image>
</view>
<view
:style="{
height: capsuleHeight + 'px',
lineHeight: capsuleHeight + 'px',
}"
class="navbar-title"
>{{ title }}
</view>
<view
:style="{
height: capsuleHeight + 'px',
lineHeight: capsuleHeight + 'px',
}"
class="navbar-right"
>
<slot name="right"></slot>
</view>
</view>
</view>
</template>
<script>
import CommonEnum from "../../enum/common";
export default {
name: "CustomNavbar",
props: {
title: {
type: String,
default: "",
},
backIcon: {
type: String,
default: CommonEnum.BACK_BUTTON,
},
showBack: {
type: Boolean,
default: true,
},
// 新增:滚动相关配置
backgroundColor: {
type: String,
default: CommonEnum.BASE_COLOR, // 滚动时的背景色,使用基调颜色
},
scrollThreshold: {
type: Number,
default: 20, // 滚动阈值,超过此值开始变色
},
enableScrollEffect: {
type: Boolean,
default: true, // 是否启用滚动效果
},
},
data() {
return {
statusBarHeight: 0,
navBarHeight: 0,
menuButtonInfo: null,
capsuleHeight: 0,
// 新增:滚动状态
isScrolled: false,
scrollTop: 0,
lastScrollTop: 0,
};
},
mounted() {
this.getSystemInfo();
},
methods: {
getSystemInfo() {
// 获取系统信息
const systemInfo = uni.getSystemInfoSync();
// 获取状态栏高度
this.statusBarHeight = systemInfo.statusBarHeight;
// 获取胶囊按钮信息
this.menuButtonInfo = uni.getMenuButtonBoundingClientRect();
// 计算胶囊高度
this.capsuleHeight = this.menuButtonInfo.height;
// 计算导航栏高度(胶囊底部到状态栏顶部的距离)
this.navBarHeight = this.menuButtonInfo.bottom + 8;
},
handleBack() {
if (this.showBack) {
// 先触发自定义事件,让父组件有机会处理
this.$emit("back");
// 自动执行返回逻辑
uni.navigateBack({
delta: 1,
fail: () => {
// 如果没有上一页,跳转到首页
uni.reLaunch({
url: "/pages/index/index", // 确保路径正确
});
},
});
}
},
// 新增:处理页面滚动(供父组件调用)
handlePageScroll(e) {
if (!this.enableScrollEffect) return;
this.scrollTop = e.scrollTop;
// 判断是否超过滚动阈值
if (this.scrollTop > this.scrollThreshold) {
if (!this.isScrolled) {
this.isScrolled = true;
this.$emit("scroll-change", {
isScrolled: true,
scrollTop: this.scrollTop,
});
}
} else {
if (this.isScrolled) {
this.isScrolled = false;
this.$emit("scroll-change", {
isScrolled: false,
scrollTop: this.scrollTop,
});
}
}
// 触发滚动事件,让父组件可以获取滚动信息
this.$emit("scroll", {
scrollTop: this.scrollTop,
isScrolled: this.isScrolled,
});
},
// 新增:手动设置滚动状态(供父组件调用)
setScrollState(scrollTop) {
if (!this.enableScrollEffect) return;
this.scrollTop = scrollTop;
this.isScrolled = scrollTop > this.scrollThreshold;
},
},
};
</script>
<style lang="scss" scoped>
/* 填充区样式 */
.navbar-placeholder {
width: 100%;
background-color: transparent;
}
/* 自定义导航栏样式 */
.custom-navbar {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 999;
padding-top: 0;
background-color: transparent;
display: flex;
align-items: center;
justify-content: space-between;
padding-left: 30rpx;
padding-right: 30rpx;
box-sizing: border-box;
transition: background-color 0.3s ease; /* 添加过渡动画 */
}
/* 滚动状态样式 */
.navbar-scrolled {
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1); /* 滚动时添加阴影 */
}
.navbar-left {
display: flex;
align-items: center;
justify-content: center;
width: 60rpx;
.back-icon {
width: 56rpx;
height: 56rpx;
}
}
.navbar-title {
font-size: 36rpx;
font-weight: bold;
color: #695347;
flex: 1;
text-align: center;
display: flex;
align-items: center;
justify-content: center;
}
.navbar-right {
width: 60rpx;
display: flex;
align-items: center;
justify-content: center;
}
</style>