feat: 添加图标库依赖并优化首页按钮动画
添加@iconify-json/ph图标库依赖 在nuxt.config.ts中配置vite优化依赖 更新社交媒体图标为ph:x-logo 实现首页"Talk"按钮的悬停动画效果
This commit is contained in:
@@ -22,6 +22,57 @@ const studioNameRef = ref<HTMLElement | null>(null)
|
|||||||
const talkBtnRef = ref<HTMLElement | null>(null)
|
const talkBtnRef = ref<HTMLElement | null>(null)
|
||||||
|
|
||||||
let cleanupHeroScroll: (() => void) | null = null
|
let cleanupHeroScroll: (() => void) | null = null
|
||||||
|
let talkBtnTl: gsap.core.Timeline | null = null
|
||||||
|
|
||||||
|
const initTalkButton = () => {
|
||||||
|
if (!talkBtnRef.value) return
|
||||||
|
|
||||||
|
const hoverBg = talkBtnRef.value.querySelector<HTMLElement>('.btn-bg-hover')
|
||||||
|
const origChars = gsap.utils.toArray<HTMLElement>('.btn-char-orig', talkBtnRef.value)
|
||||||
|
const cloneChars = gsap.utils.toArray<HTMLElement>('.btn-char-clone', talkBtnRef.value)
|
||||||
|
|
||||||
|
if (!hoverBg || !origChars.length || !cloneChars.length) return
|
||||||
|
|
||||||
|
gsap.set(hoverBg, { yPercent: 110 })
|
||||||
|
gsap.set(origChars, { yPercent: 0 })
|
||||||
|
gsap.set(cloneChars, { yPercent: 110 })
|
||||||
|
}
|
||||||
|
|
||||||
|
const onTalkHover = () => {
|
||||||
|
if (!talkBtnRef.value) return
|
||||||
|
|
||||||
|
const hoverBg = talkBtnRef.value.querySelector<HTMLElement>('.btn-bg-hover')
|
||||||
|
const origChars = gsap.utils.toArray<HTMLElement>('.btn-char-orig', talkBtnRef.value)
|
||||||
|
const cloneChars = gsap.utils.toArray<HTMLElement>('.btn-char-clone', talkBtnRef.value)
|
||||||
|
|
||||||
|
if (!hoverBg || !origChars.length || !cloneChars.length) return
|
||||||
|
|
||||||
|
talkBtnTl?.kill()
|
||||||
|
talkBtnTl = gsap.timeline({ defaults: { ease: 'power3.out' } })
|
||||||
|
|
||||||
|
talkBtnTl
|
||||||
|
.to(hoverBg, { yPercent: 0, duration: 0.42 }, 0)
|
||||||
|
.to(origChars, { yPercent: -115, duration: 0.42, stagger: 0.018 }, 0)
|
||||||
|
.to(cloneChars, { yPercent: 0, duration: 0.42, stagger: 0.018 }, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
const onTalkLeave = () => {
|
||||||
|
if (!talkBtnRef.value) return
|
||||||
|
|
||||||
|
const hoverBg = talkBtnRef.value.querySelector<HTMLElement>('.btn-bg-hover')
|
||||||
|
const origChars = gsap.utils.toArray<HTMLElement>('.btn-char-orig', talkBtnRef.value)
|
||||||
|
const cloneChars = gsap.utils.toArray<HTMLElement>('.btn-char-clone', talkBtnRef.value)
|
||||||
|
|
||||||
|
if (!hoverBg || !origChars.length || !cloneChars.length) return
|
||||||
|
|
||||||
|
talkBtnTl?.kill()
|
||||||
|
talkBtnTl = gsap.timeline({ defaults: { ease: 'power3.out' } })
|
||||||
|
|
||||||
|
talkBtnTl
|
||||||
|
.to(hoverBg, { yPercent: 110, duration: 0.42 }, 0)
|
||||||
|
.to(origChars, { yPercent: 0, duration: 0.42, stagger: 0.018 }, 0)
|
||||||
|
.to(cloneChars, { yPercent: 110, duration: 0.42, stagger: 0.018 }, 0)
|
||||||
|
}
|
||||||
|
|
||||||
// 暴露供外部(如 index.vue)使用的异步播放方法
|
// 暴露供外部(如 index.vue)使用的异步播放方法
|
||||||
const play = () => new Promise<void>((resolve) => {
|
const play = () => new Promise<void>((resolve) => {
|
||||||
@@ -89,6 +140,7 @@ onMounted(() => {
|
|||||||
if (heroRef.value) gsap.set(heroRef.value, { yPercent: 100 })
|
if (heroRef.value) gsap.set(heroRef.value, { yPercent: 100 })
|
||||||
// 初始化滚动监听逻辑
|
// 初始化滚动监听逻辑
|
||||||
setupHeroScroll()
|
setupHeroScroll()
|
||||||
|
initTalkButton()
|
||||||
})
|
})
|
||||||
const setupHeroScroll = () => {
|
const setupHeroScroll = () => {
|
||||||
if (!heroStageRef.value || !heroPanelRef.value) return
|
if (!heroStageRef.value || !heroPanelRef.value) return
|
||||||
@@ -138,6 +190,7 @@ const setupHeroScroll = () => {
|
|||||||
|
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
cleanupHeroScroll?.()
|
cleanupHeroScroll?.()
|
||||||
|
talkBtnTl?.kill()
|
||||||
})
|
})
|
||||||
|
|
||||||
defineExpose({ play })
|
defineExpose({ play })
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ onUnmounted(() => {
|
|||||||
<Icon name="ph:instagram-logo" class="w-4 h-4" />
|
<Icon name="ph:instagram-logo" class="w-4 h-4" />
|
||||||
</a>
|
</a>
|
||||||
<a href="#" class="w-10 h-10 rounded-full bg-[#1f1f1f] hover:bg-[#2f2f2f] flex items-center justify-center transition-colors text-white">
|
<a href="#" class="w-10 h-10 rounded-full bg-[#1f1f1f] hover:bg-[#2f2f2f] flex items-center justify-center transition-colors text-white">
|
||||||
<Icon name="pajamas:twitter-x" class="w-3.5 h-3.5" />
|
<Icon name="ph:x-logo" class="w-4 h-4" />
|
||||||
</a>
|
</a>
|
||||||
<a href="#" class="w-10 h-10 rounded-full bg-[#1f1f1f] hover:bg-[#2f2f2f] flex items-center justify-center transition-colors text-white">
|
<a href="#" class="w-10 h-10 rounded-full bg-[#1f1f1f] hover:bg-[#2f2f2f] flex items-center justify-center transition-colors text-white">
|
||||||
<Icon name="ph:diamond-fill" class="w-4 h-4" />
|
<Icon name="ph:diamond-fill" class="w-4 h-4" />
|
||||||
|
|||||||
@@ -6,6 +6,15 @@ export default defineNuxtConfig({
|
|||||||
viewport: 'width=device-width, initial-scale=1, maximum-scale=1',
|
viewport: 'width=device-width, initial-scale=1, maximum-scale=1',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
vite: {
|
||||||
|
optimizeDeps: {
|
||||||
|
include: [
|
||||||
|
'lenis',
|
||||||
|
'gsap',
|
||||||
|
'gsap/ScrollTrigger',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
compatibilityDate: '2025-07-15',
|
compatibilityDate: '2025-07-15',
|
||||||
devtools: { enabled: true },
|
devtools: { enabled: true },
|
||||||
css: ['~/assets/css/tailwind.css'],
|
css: ['~/assets/css/tailwind.css'],
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
"vue-router": "^5.0.4"
|
"vue-router": "^5.0.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@iconify-json/ph": "1.2.2",
|
||||||
"@nuxtjs/tailwindcss": "6.14.0"
|
"@nuxtjs/tailwindcss": "6.14.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Generated
+10
@@ -39,6 +39,9 @@ importers:
|
|||||||
specifier: ^5.0.4
|
specifier: ^5.0.4
|
||||||
version: 5.0.6(@vue/compiler-sfc@3.5.33)(pinia@3.0.4(typescript@6.0.3)(vue@3.5.33(typescript@6.0.3)))(vue@3.5.33(typescript@6.0.3))
|
version: 5.0.6(@vue/compiler-sfc@3.5.33)(pinia@3.0.4(typescript@6.0.3)(vue@3.5.33(typescript@6.0.3)))(vue@3.5.33(typescript@6.0.3))
|
||||||
devDependencies:
|
devDependencies:
|
||||||
|
'@iconify-json/ph':
|
||||||
|
specifier: 1.2.2
|
||||||
|
version: 1.2.2
|
||||||
'@nuxtjs/tailwindcss':
|
'@nuxtjs/tailwindcss':
|
||||||
specifier: 6.14.0
|
specifier: 6.14.0
|
||||||
version: 6.14.0(magicast@0.5.2)(yaml@2.8.3)
|
version: 6.14.0(magicast@0.5.2)(yaml@2.8.3)
|
||||||
@@ -595,6 +598,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==}
|
resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==}
|
||||||
engines: {node: '>=18.18'}
|
engines: {node: '>=18.18'}
|
||||||
|
|
||||||
|
'@iconify-json/ph@1.2.2':
|
||||||
|
resolution: {integrity: sha512-PgkEZNtqa8hBGjHXQa4pMwZa93hmfu8FUSjs/nv4oUU6yLsgv+gh9nu28Kqi8Fz9CCVu4hj1MZs9/60J57IzFw==}
|
||||||
|
|
||||||
'@iconify/collections@1.0.676':
|
'@iconify/collections@1.0.676':
|
||||||
resolution: {integrity: sha512-dtV8s0QtP0fjsIZoCA4gURBp2DWGs7vJDz+Kh5+vpeNinBbtbNz+MABDz61ikcFGE27mdvNFmA3ygprBXHZJ4A==}
|
resolution: {integrity: sha512-dtV8s0QtP0fjsIZoCA4gURBp2DWGs7vJDz+Kh5+vpeNinBbtbNz+MABDz61ikcFGE27mdvNFmA3ygprBXHZJ4A==}
|
||||||
|
|
||||||
@@ -5348,6 +5354,10 @@ snapshots:
|
|||||||
|
|
||||||
'@humanwhocodes/retry@0.4.3': {}
|
'@humanwhocodes/retry@0.4.3': {}
|
||||||
|
|
||||||
|
'@iconify-json/ph@1.2.2':
|
||||||
|
dependencies:
|
||||||
|
'@iconify/types': 2.0.0
|
||||||
|
|
||||||
'@iconify/collections@1.0.676':
|
'@iconify/collections@1.0.676':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@iconify/types': 2.0.0
|
'@iconify/types': 2.0.0
|
||||||
|
|||||||
Reference in New Issue
Block a user