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"
/>
相关推荐
烛阴9 分钟前
Claude CLI AskUserQuestion 工具详解:让 AI 开口问你
前端·claude
wal131452022 分钟前
OpenClaw教程(九)—— 彻底告别!OpenClaw 卸载不残留指南
前端·网络·人工智能·chrome·安全·openclaw
mon_star°39 分钟前
在TypeScript中,接口MenuItem定义中,为什么有的属性带问号?,有的不带呢?
前端
牛奶1 小时前
分享一个开源项目,让 AI 辅助开发真正高效起来
前端·人工智能·全栈
次顶级2 小时前
表单多文件上传和其他参数处理
前端·javascript·html
why技术2 小时前
我拿到了腾讯QClaw的内测码,然后沉默了。
前端·后端
小一梦2 小时前
宝塔面板单域名部署多个 Vue 项目:从路径冲突到完美共存
服务器·javascript·vue.js
谪星·阿凯3 小时前
XSS漏洞解析博客
前端·web安全·xss
ole ' ola3 小时前
lambda表达式
java·前端·jvm