524 lines
13 KiB
Vue
524 lines
13 KiB
Vue
<template>
|
||
<view class="common-header" :style="{ height: headerHeight + 'px' }">
|
||
<!-- 状态栏占位 -->
|
||
<view class="status-bar" :style="{ height: statusBarHeight + 'px' }"></view>
|
||
|
||
<!-- 自定义导航栏 -->
|
||
<view class="nav-bar" :style="{ height: navBarHeight + 'px' }">
|
||
<!-- 左侧返回按钮 -->
|
||
<view class="nav-left" @click="handleBack">
|
||
<uni-icons :type="leftIcon" size="20" :color="textColor" />
|
||
</view>
|
||
|
||
<!-- 标题区域 - 调整到胶囊位置 -->
|
||
<view class="nav-title" :style="titleStyle">
|
||
<text class="title-text" :style="{ color: textColor }">{{ title }}</text>
|
||
</view>
|
||
|
||
<!-- 右侧按钮区域 - 调整到胶囊左侧 -->
|
||
<view class="nav-right" :style="rightButtonStyle" v-if="$slots.right">
|
||
<slot name="right"></slot>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 自定义渐变背景 -->
|
||
<view class="header-bg" :style="{ background: gradientBg }"></view>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
export default {
|
||
name: 'CommonHeader',
|
||
props: {
|
||
title: {
|
||
type: String,
|
||
default: ''
|
||
},
|
||
leftIcon: {
|
||
type: String,
|
||
default: 'back'
|
||
},
|
||
backgroundColor: {
|
||
type: String,
|
||
default: 'transparent'
|
||
},
|
||
textColor: {
|
||
type: String,
|
||
default: '#000'
|
||
},
|
||
theme: {
|
||
type: String,
|
||
default: 'primary'
|
||
}
|
||
},
|
||
|
||
data() {
|
||
return {
|
||
statusBarHeight: 0,
|
||
navBarHeight: 44,
|
||
menuButtonInfo: null
|
||
}
|
||
},
|
||
|
||
computed: {
|
||
headerHeight() {
|
||
return this.statusBarHeight + this.navBarHeight
|
||
},
|
||
|
||
gradientBg() {
|
||
const themes = {
|
||
primary: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
|
||
success: 'linear-gradient(135deg, #4facfe 0%, #00f2fe 100%)',
|
||
warning: 'linear-gradient(135deg, #fa709a 0%, #fee140 100%)',
|
||
error: 'linear-gradient(135deg, #ff758c 0%, #ff7eb3 100%)',
|
||
activity: 'linear-gradient(135deg, #ff9a9e 0%, #fecfef 100%)',
|
||
rebate: 'linear-gradient(135deg, #a8edea 0%, #fed6e3 100%)',
|
||
newproduct: 'linear-gradient(135deg, #d299c2 0%, #fef9d7 100%)',
|
||
distiller: 'linear-gradient(135deg, #89f7fe 0%, #66a6ff 100%)',
|
||
order: 'linear-gradient(135deg, #fdbb2d 0%, #22c1c3 100%)',
|
||
shipping: 'linear-gradient(135deg, #e0c3fc 0%, #9bb5ff 100%)',
|
||
common: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)'
|
||
}
|
||
return themes[this.theme] || themes.primary
|
||
},
|
||
|
||
titleStyle() {
|
||
if (!this.menuButtonInfo) return {}
|
||
|
||
// 计算标题位置,使其与胶囊垂直居中对齐
|
||
const titleTop = (this.menuButtonInfo.top - this.statusBarHeight) + 'px'
|
||
const titleHeight = this.menuButtonInfo.height + 'px'
|
||
const titleRight = (this.menuButtonInfo.left - 20) + 'px' // 胶囊左侧留20px间距
|
||
|
||
return {
|
||
top: titleTop,
|
||
height: titleHeight,
|
||
right: titleRight
|
||
}
|
||
},
|
||
|
||
rightButtonStyle() {
|
||
if (!this.menuButtonInfo) return {}
|
||
|
||
// 右侧按钮定位到胶囊左侧
|
||
const buttonTop = (this.menuButtonInfo.top - this.statusBarHeight) + 'px'
|
||
const buttonHeight = this.menuButtonInfo.height + 'px'
|
||
const buttonRight = (this.menuButtonInfo.left - 10) + 'px' // 胶囊左侧留10px间距
|
||
|
||
return {
|
||
top: buttonTop,
|
||
height: buttonHeight,
|
||
right: buttonRight
|
||
}
|
||
}
|
||
},
|
||
|
||
mounted() {
|
||
this.initHeaderInfo()
|
||
this.setHeaderHeightCssVar()
|
||
},
|
||
|
||
updated() {
|
||
this.setHeaderHeightCssVar()
|
||
},
|
||
|
||
methods: {
|
||
initHeaderInfo() {
|
||
// 获取系统信息
|
||
const systemInfo = uni.getSystemInfoSync()
|
||
this.statusBarHeight = systemInfo.statusBarHeight || 0
|
||
|
||
// 获取胶囊按钮信息
|
||
// #ifdef MP-WEIXIN
|
||
try {
|
||
this.menuButtonInfo = uni.getMenuButtonBoundingClientRect()
|
||
// 根据胶囊按钮调整导航栏高度,确保合适的显示
|
||
if (this.menuButtonInfo) {
|
||
const topGap = this.menuButtonInfo.top - this.statusBarHeight
|
||
const bottomGap = topGap
|
||
this.navBarHeight = topGap + this.menuButtonInfo.height + bottomGap
|
||
}
|
||
} catch (e) {
|
||
console.warn('获取胶囊按钮信息失败:', e)
|
||
this.navBarHeight = 44
|
||
}
|
||
// #endif
|
||
|
||
// #ifdef APP-PLUS
|
||
// App端适配
|
||
this.navBarHeight = 44
|
||
// #endif
|
||
|
||
// #ifdef H5
|
||
// H5端适配
|
||
this.navBarHeight = 44
|
||
// #endif
|
||
|
||
// #ifndef MP-WEIXIN || APP-PLUS || H5
|
||
// 其他平台使用默认值
|
||
this.navBarHeight = 44
|
||
// #endif
|
||
|
||
// 确保最小高度
|
||
if (this.navBarHeight < 44) {
|
||
this.navBarHeight = 44
|
||
}
|
||
},
|
||
|
||
handleBack() {
|
||
this.$emit('back')
|
||
uni.navigateBack({
|
||
fail: () => {
|
||
uni.switchTab({
|
||
url: '/pages/work/index'
|
||
})
|
||
}
|
||
})
|
||
},
|
||
|
||
// 设置CSS变量,供其他组件使用
|
||
setHeaderHeightCssVar() {
|
||
this.$nextTick(() => {
|
||
const headerHeight = this.headerHeight
|
||
// #ifdef H5
|
||
document.documentElement.style.setProperty('--header-height', headerHeight + 'px')
|
||
// #endif
|
||
|
||
// 为小程序和App动态设置头部间距
|
||
this.updatePagePadding(headerHeight)
|
||
|
||
// 向父组件发送头部高度信息
|
||
this.$emit('header-info', {
|
||
headerHeight: headerHeight,
|
||
statusBarHeight: this.statusBarHeight,
|
||
navBarHeight: this.navBarHeight
|
||
})
|
||
})
|
||
},
|
||
|
||
// 动态更新页面内容的padding-top
|
||
updatePagePadding(headerHeight) {
|
||
// #ifdef H5
|
||
try {
|
||
const cssSelectors = [
|
||
'.page-content',
|
||
'.activity-content',
|
||
'.rebate-content',
|
||
'.newproduct-content',
|
||
'.distiller-content',
|
||
'.order-content',
|
||
'.shipping-content',
|
||
'.activity-container',
|
||
'.rebate-container',
|
||
'.newproduct-container',
|
||
'.distiller-container',
|
||
'.order-container',
|
||
'.shipping-container',
|
||
'.add-content',
|
||
'.edit-content',
|
||
'.detail-content',
|
||
'.batch-content',
|
||
'.transfer-content',
|
||
'.history-content',
|
||
'.logistics-content',
|
||
'.destroy-container .page-content'
|
||
]
|
||
|
||
// 创建动态样式
|
||
const dynamicStyle = cssSelectors.map(selector => {
|
||
return `${selector} { padding-top: ${headerHeight}px !important; }`
|
||
}).join('\n')
|
||
|
||
// 添加或更新style标签
|
||
let styleElement = document.getElementById('common-header-dynamic-style')
|
||
if (!styleElement) {
|
||
styleElement = document.createElement('style')
|
||
styleElement.id = 'common-header-dynamic-style'
|
||
document.head.appendChild(styleElement)
|
||
}
|
||
styleElement.textContent = dynamicStyle
|
||
} catch (e) {
|
||
console.warn('更新页面间距失败:', e)
|
||
}
|
||
// #endif
|
||
|
||
// #ifdef MP-WEIXIN || APP-PLUS
|
||
// 小程序和App中通过事件通知父页面更新样式
|
||
uni.$emit('header-height-updated', {
|
||
headerHeight: headerHeight,
|
||
statusBarHeight: this.statusBarHeight,
|
||
navBarHeight: this.navBarHeight
|
||
})
|
||
|
||
// 设置全局数据供其他组件使用
|
||
try {
|
||
const app = getApp()
|
||
if (app) {
|
||
app.globalData = app.globalData || {}
|
||
app.globalData.headerHeight = headerHeight
|
||
app.globalData.statusBarHeight = this.statusBarHeight
|
||
app.globalData.navBarHeight = this.navBarHeight
|
||
}
|
||
} catch (e) {
|
||
console.warn('设置全局头部高度失败:', e)
|
||
}
|
||
// #endif
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.common-header {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
width: 100%;
|
||
z-index: 999;
|
||
|
||
.header-bg {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
z-index: -1;
|
||
}
|
||
|
||
.status-bar {
|
||
width: 100%;
|
||
background: transparent;
|
||
}
|
||
|
||
.nav-bar {
|
||
position: relative;
|
||
display: flex;
|
||
align-items: center;
|
||
width: 100%;
|
||
padding: 0 20rpx;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.nav-left {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
width: 80rpx;
|
||
height: 80rpx;
|
||
border-radius: 50%;
|
||
background: rgba(255, 255, 255, 0.1);
|
||
backdrop-filter: blur(10px);
|
||
cursor: pointer;
|
||
transition: all 0.3s ease;
|
||
|
||
&:hover {
|
||
background: rgba(255, 255, 255, 0.2);
|
||
}
|
||
|
||
&:active {
|
||
transform: scale(0.95);
|
||
}
|
||
}
|
||
|
||
.nav-title {
|
||
position: absolute;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
left: 120rpx;
|
||
z-index: 1;
|
||
|
||
.title-text {
|
||
font-size: 32rpx;
|
||
font-weight: 600;
|
||
text-align: center;
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
max-width: 400rpx;
|
||
text-shadow: 0 1px 3px rgba(255, 255, 255, 0.8);
|
||
}
|
||
}
|
||
|
||
.nav-right {
|
||
position: absolute;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
z-index: 2;
|
||
|
||
// 右侧按钮样式美化
|
||
::v-deep .uni-icons {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
width: 60rpx;
|
||
height: 60rpx;
|
||
border-radius: 50%;
|
||
background: rgba(255, 255, 255, 0.15);
|
||
backdrop-filter: blur(10px);
|
||
transition: all 0.3s ease;
|
||
|
||
&:hover {
|
||
background: rgba(255, 255, 255, 0.25);
|
||
}
|
||
|
||
&:active {
|
||
transform: scale(0.95);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 适配不同主题的文字颜色
|
||
.common-header.dark {
|
||
.nav-left,
|
||
.nav-right ::v-deep .uni-icons {
|
||
background: rgba(0, 0, 0, 0.1);
|
||
|
||
&:hover {
|
||
background: rgba(0, 0, 0, 0.2);
|
||
}
|
||
}
|
||
}
|
||
|
||
// 适配不同设备
|
||
/* #ifdef H5 */
|
||
.common-header {
|
||
.nav-left,
|
||
.nav-right ::v-deep .uni-icons {
|
||
cursor: pointer;
|
||
}
|
||
}
|
||
/* #endif */
|
||
|
||
/* #ifdef MP-WEIXIN */
|
||
.common-header {
|
||
.nav-title {
|
||
// 小程序中的标题位置微调
|
||
.title-text {
|
||
font-size: 30rpx;
|
||
}
|
||
}
|
||
}
|
||
/* #endif */
|
||
</style>
|
||
|
||
<!-- 全局样式,为其他页面提供头部间距 -->
|
||
<style lang="scss">
|
||
// 为页面内容提供合适的顶部间距
|
||
.page-content,
|
||
.activity-content,
|
||
.rebate-content,
|
||
.newproduct-content,
|
||
.distiller-content,
|
||
.order-content,
|
||
.shipping-content {
|
||
padding-top: var(--header-height, 88px);
|
||
min-height: 100vh;
|
||
box-sizing: border-box;
|
||
padding-left: 20rpx;
|
||
padding-right: 20rpx;
|
||
padding-bottom: 20rpx;
|
||
}
|
||
|
||
// 为使用CommonHeader的页面容器提供头部间距
|
||
.activity-container,
|
||
.rebate-container,
|
||
.newproduct-container,
|
||
.distiller-container,
|
||
.order-container,
|
||
.shipping-container {
|
||
padding-top: var(--header-height, 88px);
|
||
min-height: 100vh;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
// 添加和编辑页面的内容区域
|
||
.add-content,
|
||
.edit-content,
|
||
.detail-content,
|
||
.batch-content,
|
||
.transfer-content,
|
||
.history-content,
|
||
.logistics-content {
|
||
padding-top: var(--header-height, 88px);
|
||
padding-left: 20rpx;
|
||
padding-right: 20rpx;
|
||
padding-bottom: 20rpx;
|
||
min-height: calc(100vh - var(--header-height, 88px));
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
// 销毁酒类页面特殊处理
|
||
.destroy-container .page-content {
|
||
padding-top: var(--header-height, 88px);
|
||
}
|
||
|
||
// 在小程序中的特殊处理 - 使用计算的实际高度
|
||
/* #ifdef MP-WEIXIN */
|
||
.page-content,
|
||
.activity-content,
|
||
.rebate-content,
|
||
.newproduct-content,
|
||
.distiller-content,
|
||
.order-content,
|
||
.shipping-content,
|
||
.activity-container,
|
||
.rebate-container,
|
||
.newproduct-container,
|
||
.distiller-container,
|
||
.order-container,
|
||
.shipping-container {
|
||
padding-top: 96px; // 状态栏(44px) + 导航栏(52px) 的常见值
|
||
}
|
||
|
||
.add-content,
|
||
.edit-content,
|
||
.detail-content,
|
||
.batch-content,
|
||
.transfer-content,
|
||
.history-content,
|
||
.logistics-content {
|
||
padding-top: 96px; // 状态栏(44px) + 导航栏(52px) 的常见值
|
||
}
|
||
|
||
.destroy-container .page-content {
|
||
padding-top: 96px; // 状态栏(44px) + 导航栏(52px) 的常见值
|
||
}
|
||
/* #endif */
|
||
|
||
// 在App中的特殊处理
|
||
/* #ifdef APP-PLUS */
|
||
.page-content,
|
||
.activity-content,
|
||
.rebate-content,
|
||
.newproduct-content,
|
||
.distiller-content,
|
||
.order-content,
|
||
.shipping-content,
|
||
.activity-container,
|
||
.rebate-container,
|
||
.newproduct-container,
|
||
.distiller-container,
|
||
.order-container,
|
||
.shipping-container {
|
||
padding-top: calc(44px + var(--status-bar-height, 20px));
|
||
}
|
||
|
||
.add-content,
|
||
.edit-content,
|
||
.detail-content,
|
||
.batch-content,
|
||
.transfer-content,
|
||
.history-content,
|
||
.logistics-content {
|
||
padding-top: calc(44px + var(--status-bar-height, 20px));
|
||
}
|
||
|
||
.destroy-container .page-content {
|
||
padding-top: calc(44px + var(--status-bar-height, 20px));
|
||
}
|
||
/* #endif */
|
||
</style> |