组件封装还是不完全 少一些自动化的东西 希望有大佬可以指点下
javascript
<script lang="ts" setup>
import { computed } from 'vue'
const props = defineProps<{
// 主题色
themeColor?: string
// 渐变起始透明度
startOpacity?: number
// 渐变结束透明度
endOpacity?: number
// 触发完全渐变的滚动距离
threshold?: number
// 是否显示标题
showTitle?: boolean
// 标题文本
title?: string
// 滚动距离(从父组件传入)
scrollTop?: number
// 是否显示返回按钮
isToBack?: boolean
// 是否显示返回主页按钮
isToHome?: boolean
// 是否显示右侧按钮
isToRightBack?: boolean
}>()
const emit = defineEmits<{
(e: 'back'): void
(e: 'rightClick'): void
}>()
// 默认值
const defaultThemeColor = '#1e88e5' // 蓝色主题色
const defaultStartOpacity = 0
const defaultEndOpacity = 1
const defaultThreshold = 100
// 当前透明度
const opacity = computed(() => {
const scrollTopVal = props.scrollTop || 0
const threshold = props.threshold || defaultThreshold
const startOpacity = props.startOpacity || defaultStartOpacity
const endOpacity = props.endOpacity || defaultEndOpacity
// 计算透明度,从startOpacity到endOpacity渐变
const opacityRange = endOpacity - startOpacity
const scrollProgress = Math.min(scrollTopVal / threshold, 1)
return startOpacity + (opacityRange * scrollProgress)
})
// 计算当前背景色
const bgColor = computed(() => {
const color = props.themeColor || defaultThemeColor
const currentOpacity = opacity.value
// 将16进制颜色转换为rgba
const hex = color.replace('#', '')
const r = Number.parseInt(hex.substring(0, 2), 16)
const g = Number.parseInt(hex.substring(2, 4), 16)
const b = Number.parseInt(hex.substring(4, 6), 16)
return `rgba(${r}, ${g}, ${b}, ${currentOpacity})`
})
// 计算文字颜色
const textColor = computed(() => {
return opacity.value > 0.5 ? '#ffffff' : '#000000'
})
// 处理返回按钮点击
function handleBack() {
emit('back')
}
// 处理返回主页点击
function handleBackHome() {
emit('backHome')
}
// 处理右侧按钮点击
function handleRightClick() {
emit('rightClick')
}
</script>
<template>
<view class="gradient-header" :style="{ backgroundColor: bgColor }">
<view class="header-content flex items-center justify-between px-4">
<!-- 左侧返回按钮 -->
<view v-if="isToBack" class="header-left" @click="handleBack">
<text class="text-lg" :style="{ color: textColor }">
<uv-icon name="arrow-left" />
</text>
</view>
<!-- 返回主页 -->
<view v-if="isToHome" class="header-left header-left-home" @click="handleBackHome">
<text class="text-lg" :style="{ color: textColor }">
<uv-icon name="home" />
</text>
</view>
<!-- 中间标题 -->
<view v-if="showTitle" class="header-center flex-1 text-center" :style="{ color: textColor }">
{{ title || '' }}
</view>
<view v-else class="header-center flex-1" />
<!-- 右侧按钮 -->
<view v-if="isToRightBack" class="header-right" @click="handleRightClick">
<text class="text-lg" :style="{ color: textColor }">···</text>
</view>
</view>
</view>
</template>
<style scoped>
.gradient-header {
position: fixed;
top: 0;
left: 0;
right: 0;
height: 88rpx;
z-index: 999;
transition: background-color 0.3s ease;
}
.header-content {
height: 100%;
line-height: 100%;
}
.header-left {
position: absolute;
top: 50%;
left: 30rpx;
transform: translateY(-50%);
border-radius: 50%;
background: rgba(255, 255, 255, 0.1);
border: 2rpx solid rgba(0, 0, 0, 0.2);
width: 30px;
height: 30px;
display: flex;
align-items: center;
justify-content: center;
}
.header-left-home {
position: absolute;
top: 50%;
left: 100rpx;
transform: translateY(-50%);
border-radius: 50%;
background: rgba(255, 255, 255, 0.1);
border: 2rpx solid rgba(0, 0, 0, 0.2);
width: 30px;
height: 30px;
display: flex;
align-items: center;
justify-content: center;
}
</style>
import GradientHeader from '@/components/GradientHeader.vue'
// 滚动距离
const scrollTop = ref(0)
// 处理页面滚动事件(uni-app 生命周期函数)
onPageScroll((e: any) => {
scrollTop.value = e?.scrollTop || 0
})
<!-- 渐变头部 -->
<GradientHeader
theme-color="#6283d4" :start-opacity="0" :end-opacity="1" :threshold="100" :show-title="true"
title="首页" :scroll-top="scrollTop" :is-to-back="false" :is-to-right-back="false" @back="handleBack"
@right-click="handleRightClick"
/>