044042fe7e
- 新增 AppLoader 组件作为全局加载器 - 引入 Pinia 状态管理应用加载状态 - 创建 usePageScrollLock 组合式函数管理滚动锁定 - 重构首页动画流程,使用 Promise 链式调用 - 移除旧的 HomeLoader 组件 - 优化头部导航栏的入场动画触发逻辑
84 lines
2.3 KiB
Vue
84 lines
2.3 KiB
Vue
<script setup lang="ts">
|
|
import { computed, ref, watch } from 'vue'
|
|
import { useI18n } from 'vue-i18n'
|
|
import { useUserStore } from '~/stores/user'
|
|
import { useAppStore } from '~/stores/app'
|
|
import { usePageScrollLock } from '~/composables/usePageScrollLock'
|
|
import HomeIntro from '~/components/home/HomeIntro.vue'
|
|
import HomeHero from '~/components/home/HomeHero.vue'
|
|
|
|
const { t } = useI18n()
|
|
const userStore = useUserStore()
|
|
const appStore = useAppStore()
|
|
|
|
const isIntroActive = ref(true)
|
|
|
|
const demoUserName = computed(() => userStore.displayName)
|
|
const demoUserRole = computed(() => userStore.role)
|
|
|
|
if (!userStore.isLoggedIn) {
|
|
userStore.loadDemoUser()
|
|
}
|
|
|
|
// 让首屏入场的锁滚动在 SSR/首帧就生效,避免等 onMounted 才隐藏滚动条。
|
|
useHead({
|
|
htmlAttrs: {
|
|
class: computed(() => (isIntroActive.value ? 'is-home-intro-active' : undefined)),
|
|
},
|
|
})
|
|
|
|
// 使用组合式函数管理 Lenis 滚动锁定
|
|
usePageScrollLock(isIntroActive)
|
|
|
|
// 首页的 SEO 和 Meta 优化,支持国际化响应式
|
|
useSeoMeta({
|
|
title: () => t('home.title'),
|
|
description: () => t('home.welcome'),
|
|
ogTitle: () => `${t('home.title')} - ${t('app.name')}`,
|
|
ogDescription: () => t('home.welcome'),
|
|
twitterTitle: () => `${t('home.title')} - ${t('app.name')}`,
|
|
twitterDescription: () => t('home.welcome'),
|
|
})
|
|
|
|
const homeIntroRef = ref<InstanceType<typeof HomeIntro> | null>(null)
|
|
const homeHeroRef = ref<InstanceType<typeof HomeHero> | null>(null)
|
|
|
|
// 监听全局加载状态,加载完成后依次播放开场和首屏动画
|
|
watch(() => appStore.isAppLoading, async (isLoading) => {
|
|
if (!isLoading) {
|
|
await homeIntroRef.value?.play()
|
|
await homeHeroRef.value?.play()
|
|
|
|
// 动画播放完毕后解除页面滚动锁定
|
|
isIntroActive.value = false
|
|
}
|
|
}, { immediate: true })
|
|
</script>
|
|
|
|
<template>
|
|
<main
|
|
id="top"
|
|
:data-demo-user="demoUserName"
|
|
:data-demo-user-role="demoUserRole"
|
|
>
|
|
<HomeIntro ref="homeIntroRef" />
|
|
<HomeHero ref="homeHeroRef" />
|
|
|
|
<section class="next-section">
|
|
<h2>Next Section</h2>
|
|
</section>
|
|
<section id="work" class="work-section" data-cursor-label="Read more">
|
|
<p>{{ t('home.welcome') }}</p>
|
|
</section>
|
|
</main>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.next-section,
|
|
.work-section {
|
|
min-height: 100svh;
|
|
display: grid;
|
|
place-items: center;
|
|
}
|
|
</style>
|