Files
arcticnewone/app/components/common/AppLogo.vue
T
virtheart be0bf01845 feat(i18n): 添加首页英雄区域的多语言支持
为首页英雄区域添加中英文翻译内容,包括服务列表、描述文本和按钮文字
同时优化AppLogo组件的动画安全检查和HomeHero组件的布局与动画效果
2026-04-27 17:51:00 +08:00

123 lines
3.1 KiB
Vue

<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount } from 'vue'
import { useRouter } from 'vue-router'
import { useI18n } from 'vue-i18n'
import gsap from 'gsap'
import { ScrollTrigger } from 'gsap/ScrollTrigger'
gsap.registerPlugin(ScrollTrigger)
const props = withDefaults(defineProps<{ showText?: boolean; compact?: boolean; clickAction?: 'home' | 'top' }>(), {
showText: true,
compact: false,
clickAction: 'home',
})
const { t } = useI18n()
const router = useRouter()
const logoRef = ref<HTMLElement | null>(null)
let logoObserver: ReturnType<typeof ScrollTrigger.observe> | null = null
const handleClick = () => {
if (props.clickAction === 'home') {
router.push('/')
return
}
if (props.clickAction === 'top' && typeof window !== 'undefined') {
window.scrollTo({ top: 0, behavior: 'smooth' })
}
}
const logoHover = () => {
if (!props.showText) return
if (!logoRef.value) return
logoObserver?.kill()
// Ensure children exist before attempting to animate them
const firstChild = logoRef.value.children[0] as HTMLElement
const secondChild = logoRef.value.children[1] as HTMLElement
if (!firstChild || !secondChild) return
gsap.set(secondChild, {
opacity: 0,
visibility: 'hidden',
y: 0,
})
logoObserver = ScrollTrigger.observe({
target: logoRef.value,
onHover: (self) => {
gsap.to(firstChild, {
y: -10,
duration: 0.3,
ease: 'power2.out',
})
gsap.to(secondChild, {
y: 10,
duration: 0.3,
ease: 'power2.out',
opacity: 1,
visibility: 'visible',
})
},
onHoverEnd: (self) => {
gsap.to(firstChild, {
y: 0,
duration: 0.3,
ease: 'power2.out',
})
gsap.to(secondChild, {
y: 0,
duration: 0.3,
ease: 'power2.out',
opacity: 0,
visibility: 'hidden',
})
},
})
}
onMounted(() => {
logoHover()
})
onBeforeUnmount(() => {
logoObserver?.kill()
if (logoRef.value) {
gsap.killTweensOf([logoRef.value.children[0], logoRef.value.children[1]])
}
})
</script>
<template>
<div class="flex items-center justify-center cursor-pointer gap-2" @click="handleClick">
<div class="logo-icon flex h-[1.8rem] w-[1.8rem] items-center justify-center rounded-full bg-black overflow-hidden">
<video
src="/assets/logo.mp4"
class="h-[220%] w-[220%] object-cover pointer-events-none"
autoplay
muted
loop
playsinline
disablepictureinpicture
disableremoteplayback
controlslist="nodownload noplaybackrate noremoteplayback"
/>
</div>
<div
v-if="props.showText"
ref="logoRef"
class="relative flex items-center overflow-hidden"
:class="props.compact ? 'h-[1.8rem]' : 'h-10'"
style="min-width: 100px;"
>
<span class="absolute left-0 text-base font-bold leading-none tracking-wider text-black">{{ t('app.brand') }}</span>
<span class="absolute left-0 text-xs leading-none text-gray-500 opacity-0 invisible">{{ t('app.name') }}</span>
</div>
</div>
</template>