uniApp下拉渐变头部 拿来即用

组件封装还是不完全 少一些自动化的东西 希望有大佬可以指点下

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"
/>
相关推荐
万物得其道者成7 小时前
前端大整数精度丢失:一次踩坑后的实战解决方案(`json-bigint`)
前端·json
鹏北海8 小时前
移动端 H5 响应式字体适配方案完全指南
前端
姜太公钓鲸2339 小时前
ROM就是程序存储器,实际的存储介质是Flash闪存。上述描述中的程序存储器是什么意思?
开发语言·javascript·ecmascript
柳杉10 小时前
使用AI从零打造炫酷医疗数据可视化大屏,源码免费拿!
前端·javascript·数据可视化
凌云拓界10 小时前
前端开发的“平衡木”:在取舍之间找到最优解
前端·性能优化·架构·前端框架·代码规范·设计规范
iOS阿玮10 小时前
百款出海社交 App 一夜下架!2026,匿名社交的生死劫怎么破?
uni-app·app·apple
zhengfei61110 小时前
【XSS payload 】一个经典的XSS payload
前端·xss
简单Janeee10 小时前
[Vue 3 从零到上线]-第四篇:组件化思维——把网页像积木一样拆解
javascript·vue.js·ecmascript
全栈老石11 小时前
手写一个无限画布 #1:坐标系的谎言
前端·canvas
XW010599912 小时前
4-11判断素数
前端·python·算法·素数