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') }}

-