142 lines
2.9 KiB
Vue
142 lines
2.9 KiB
Vue
<template>
|
||
<!-- 状态栏占位区,为刘海屏和安全区域留出空间 -->
|
||
<view class="tab-page__status-bar" :style="{ height: statusBarHeight + 'px' }"></view>
|
||
<!-- 导航栏主体 -->
|
||
<view class="tab-page__header">
|
||
<view v-if="showBack" :class="['tab-page__back-btn', { 'tab-page__back-btn--animate': isAnimating }]" @tap="goBack">
|
||
<text class="tab-page__back-icon">‹</text>
|
||
</view>
|
||
<view class="tab-page__title-wrap">
|
||
<text class="tab-page__title">{{ title }}</text>
|
||
<text v-if="subtitle" class="tab-page__subtitle">{{ subtitle }}</text>
|
||
</view>
|
||
<view v-if="$slots.right" class="tab-page__right">
|
||
<slot name="right"></slot>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, onMounted, computed } from 'vue'
|
||
|
||
const props = defineProps({
|
||
title: {
|
||
type: String,
|
||
default: '课程'
|
||
},
|
||
subtitle: {
|
||
type: String,
|
||
default: '精品团课 · 私教 · 线上课'
|
||
},
|
||
showBack: {
|
||
type: Boolean,
|
||
default: false
|
||
}
|
||
})
|
||
|
||
const isAnimating = ref(false)
|
||
const statusBarHeight = ref(0)
|
||
|
||
onMounted(() => {
|
||
// 所有平台获取状态栏高度,为刘海屏/状态栏留出安全空间
|
||
const sysInfo = uni.getSystemInfoSync()
|
||
statusBarHeight.value = sysInfo.statusBarHeight || 0
|
||
|
||
if (props.showBack) {
|
||
isAnimating.value = true
|
||
}
|
||
})
|
||
|
||
function goBack() {
|
||
uni.navigateBack({
|
||
fail: () => {
|
||
uni.switchTab({
|
||
url: '/pages/index/index'
|
||
})
|
||
}
|
||
})
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
/* 状态栏占位:适配所有平台,包含刘海屏安全区域 */
|
||
.tab-page__status-bar {
|
||
width: 100%;
|
||
/* iOS 刘海屏额外安全区域 */
|
||
padding-top: constant(safe-area-inset-top); /* iOS 11.0-11.2 */
|
||
padding-top: env(safe-area-inset-top); /* iOS 11.2+ */
|
||
box-sizing: content-box;
|
||
}
|
||
|
||
.tab-page__header {
|
||
padding: 0 32rpx 24rpx 32rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
height: 88rpx;
|
||
position: relative;
|
||
}
|
||
|
||
.tab-page__back-btn {
|
||
width: 48rpx;
|
||
height: 64rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
margin-right: 16rpx;
|
||
background: rgba(0, 0, 0, 0.06);
|
||
border-radius: 16rpx;
|
||
opacity: 0;
|
||
transform: translateX(120rpx);
|
||
transition: none;
|
||
z-index: 1;
|
||
}
|
||
|
||
.tab-page__back-btn--animate {
|
||
animation: slideInFromRight 0.4s ease-out forwards;
|
||
}
|
||
|
||
@keyframes slideInFromRight {
|
||
0% {
|
||
opacity: 0;
|
||
transform: translateX(120rpx);
|
||
}
|
||
100% {
|
||
opacity: 1;
|
||
transform: translateX(0);
|
||
}
|
||
}
|
||
|
||
.tab-page__back-icon {
|
||
font-size: 36rpx;
|
||
color: $text-dark;
|
||
font-weight: bold;
|
||
line-height: 28rpx;
|
||
}
|
||
|
||
.tab-page__title-wrap {
|
||
flex: 1;
|
||
position: relative;
|
||
z-index: 2;
|
||
}
|
||
|
||
.tab-page__title {
|
||
display: block;
|
||
font-size: 40rpx;
|
||
font-weight: $font-weight-bold;
|
||
color: $text-dark;
|
||
}
|
||
|
||
.tab-page__subtitle {
|
||
display: block;
|
||
margin-top: 8rpx;
|
||
font-size: 24rpx;
|
||
color: $text-muted;
|
||
}
|
||
|
||
.tab-page__right {
|
||
margin-left: 16rpx;
|
||
flex-shrink: 0;
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
</style> |