From 5390b70fa910ff28180136e5230f30c1cf5b7213 Mon Sep 17 00:00:00 2001
From: chenchun
Date: Mon, 27 Apr 2026 17:51:47 +0800
Subject: [PATCH] =?UTF-8?q?feat(home):=20=E4=B8=BA=E9=A6=96=E9=A1=B5?=
=?UTF-8?q?=E5=AF=B9=E8=AF=9D=E6=8C=89=E9=92=AE=E6=B7=BB=E5=8A=A0=E6=82=AC?=
=?UTF-8?q?=E5=81=9C=E5=8A=A8=E7=94=BB=E6=95=88=E6=9E=9C?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
添加GSAP动画效果,当鼠标悬停在对话按钮上时,文字会向上滑动并显示克隆文字,同时背景色块从底部滑入。离开时恢复原始状态。
---
app/components/home/HomeHero.vue | 68 +++++++++++++++++++++++++++++++-
1 file changed, 66 insertions(+), 2 deletions(-)
diff --git a/app/components/home/HomeHero.vue b/app/components/home/HomeHero.vue
index 981a6e6..79923bb 100644
--- a/app/components/home/HomeHero.vue
+++ b/app/components/home/HomeHero.vue
@@ -18,6 +18,7 @@ const heroRef = ref(null)
const heroPanelRef = ref(null)
const brandNameRef = ref(null)
const studioNameRef = ref(null)
+const talkBtnRef = ref(null)
let cleanupHeroScroll: (() => void) | null = null
@@ -112,7 +113,39 @@ const setupHeroScroll = () => {
cleanupHeroScroll = () => gsap.ticker.remove(updateHeroPanelScale)
}
+const onTalkHover = () => {
+ if (!talkBtnRef.value) return
+ const origs = talkBtnRef.value.querySelectorAll('.btn-char-orig')
+ const clones = talkBtnRef.value.querySelectorAll('.btn-char-clone')
+ const bg = talkBtnRef.value.querySelector('.btn-bg-hover')
+
+ // 背景从底部滑入 (yPercent: 100 -> 0)
+ gsap.to(bg, { yPercent: 0, duration: 0.4, ease: 'power3.out', overwrite: true })
+
+ gsap.to(origs, { yPercent: -100, duration: 0.4, stagger: { amount: 0.2, from: 'start' }, ease: 'power3.out', overwrite: true })
+ gsap.to(clones, { yPercent: 0, duration: 0.4, stagger: { amount: 0.2, from: 'start' }, ease: 'power3.out', overwrite: true })
+}
+
+const onTalkLeave = () => {
+ if (!talkBtnRef.value) return
+ const origs = talkBtnRef.value.querySelectorAll('.btn-char-orig')
+ const clones = talkBtnRef.value.querySelectorAll('.btn-char-clone')
+ const bg = talkBtnRef.value.querySelector('.btn-bg-hover')
+
+ // 背景向下反向滑出回收 (yPercent: 0 -> 100)
+ gsap.to(bg, { yPercent: 100, duration: 0.4, ease: 'power3.out', overwrite: true })
+
+ gsap.to(origs, { yPercent: 0, duration: 0.4, stagger: { amount: 0.2, from: 'end' }, ease: 'power3.out', overwrite: true })
+ gsap.to(clones, { yPercent: 100, duration: 0.4, stagger: { amount: 0.2, from: 'end' }, ease: 'power3.out', overwrite: true })
+}
+
onMounted(() => {
+ if (talkBtnRef.value) {
+ const clones = talkBtnRef.value.querySelectorAll('.btn-char-clone')
+ const bg = talkBtnRef.value.querySelector('.btn-bg-hover')
+ gsap.set(clones, { yPercent: 100 })
+ gsap.set(bg, { yPercent: 100 })
+ }
// 组件挂载时,先将整个 Hero 强行置于屏幕下方,等待外部调用 `play()` 才滑入
if (heroRef.value) gsap.set(heroRef.value, { yPercent: 100 })
// 初始化滚动监听逻辑
@@ -178,8 +211,39 @@ defineExpose({ play })
{{ t('hero.description') }}
-