1
This commit is contained in:
@@ -1,9 +1,17 @@
|
||||
import { onMounted, onUnmounted } from 'vue'
|
||||
import { onMounted, onUnmounted, nextTick } from 'vue'
|
||||
|
||||
export function useScrollAnimation() {
|
||||
let observer: IntersectionObserver | null = null
|
||||
|
||||
const observe = () => {
|
||||
const initObserver = async () => {
|
||||
// Wait for DOM updates
|
||||
await nextTick()
|
||||
|
||||
// Disconnect existing observer if any
|
||||
if (observer) {
|
||||
observer.disconnect()
|
||||
}
|
||||
|
||||
observer = new IntersectionObserver((entries) => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting) {
|
||||
@@ -17,19 +25,28 @@ export function useScrollAnimation() {
|
||||
rootMargin: '50px' // Pre-load slightly before element comes into view
|
||||
})
|
||||
|
||||
document.querySelectorAll('.animate-slide-down, .animate-reveal').forEach(el => {
|
||||
observer?.observe(el)
|
||||
})
|
||||
const elements = document.querySelectorAll('.animate-slide-down, .animate-reveal')
|
||||
if (elements.length === 0) {
|
||||
// Retry once if no elements found (e.g. data loaded but DOM not quite ready)
|
||||
setTimeout(() => {
|
||||
document.querySelectorAll('.animate-slide-down, .animate-reveal').forEach(el => {
|
||||
observer?.observe(el)
|
||||
})
|
||||
}, 100)
|
||||
} else {
|
||||
elements.forEach(el => {
|
||||
observer?.observe(el)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
// Small delay to ensure DOM is ready
|
||||
setTimeout(observe, 100)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
if (observer) {
|
||||
observer.disconnect()
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
initObserver
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,6 +111,8 @@ const profile = ref<Profile>({
|
||||
const loading = ref(false)
|
||||
const error = ref('')
|
||||
|
||||
const { initObserver } = useScrollAnimation()
|
||||
|
||||
// 模拟API调用,实际项目中应替换为真实API
|
||||
const fetchProfileData = async () => {
|
||||
loading.value = true
|
||||
@@ -134,6 +136,8 @@ const fetchProfileData = async () => {
|
||||
},
|
||||
techStack: ['Vue 3', 'React', 'TypeScript', 'Three.js', 'Golang', 'Tailwind CSS', 'Vite', 'Gin']
|
||||
}
|
||||
// 初始化动画
|
||||
initObserver()
|
||||
} catch (err) {
|
||||
console.error('Error fetching profile data:', err)
|
||||
error.value = '获取个人资料失败,请稍后重试'
|
||||
@@ -143,14 +147,8 @@ const fetchProfileData = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
onBeforeMount(() => {
|
||||
fetchProfileData()
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
// 启用滚动动画
|
||||
useScrollAnimation()
|
||||
|
||||
fetchProfileData()
|
||||
// 初始化Lucide图标
|
||||
if (window.lucide) {
|
||||
window.lucide.createIcons()
|
||||
|
||||
@@ -52,12 +52,16 @@ const blogPosts = ref<Post[]>([])
|
||||
const loading = ref(false)
|
||||
const error = ref('')
|
||||
|
||||
const { initObserver } = useScrollAnimation()
|
||||
|
||||
const fetchBlogPosts = async () => {
|
||||
loading.value = true
|
||||
error.value = ''
|
||||
try {
|
||||
const posts = await fetchPosts()
|
||||
blogPosts.value = posts
|
||||
// 初始化动画 - 在数据加载完成后
|
||||
initObserver()
|
||||
} catch (err) {
|
||||
console.error('Error fetching blog posts:', err)
|
||||
error.value = '获取博客文章失败,请稍后重试'
|
||||
@@ -66,14 +70,8 @@ const fetchBlogPosts = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
onBeforeMount(() => {
|
||||
fetchBlogPosts()
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
// 启用滚动动画
|
||||
useScrollAnimation()
|
||||
|
||||
fetchBlogPosts()
|
||||
// 初始化Lucide图标
|
||||
if (window.lucide) {
|
||||
window.lucide.createIcons()
|
||||
|
||||
@@ -81,6 +81,8 @@ const post = ref<Post>({
|
||||
const loading = ref(false)
|
||||
const error = ref('')
|
||||
|
||||
const { initObserver } = useScrollAnimation()
|
||||
|
||||
const fetchBlogDetail = async () => {
|
||||
loading.value = true
|
||||
error.value = ''
|
||||
@@ -88,6 +90,8 @@ const fetchBlogDetail = async () => {
|
||||
const postData = await fetchPost(postId)
|
||||
if (postData) {
|
||||
post.value = postData
|
||||
// 初始化动画 - 在数据加载完成后
|
||||
initObserver()
|
||||
} else {
|
||||
error.value = '未找到该文章'
|
||||
}
|
||||
@@ -99,14 +103,8 @@ const fetchBlogDetail = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
onBeforeMount(() => {
|
||||
fetchBlogDetail()
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
// 启用滚动动画
|
||||
useScrollAnimation()
|
||||
|
||||
fetchBlogDetail()
|
||||
// 初始化Lucide图标
|
||||
if (window.lucide) {
|
||||
window.lucide.createIcons()
|
||||
|
||||
@@ -108,6 +108,8 @@ import { ref, onMounted, onBeforeMount } from 'vue'
|
||||
import { fetchWorks, fetchPosts, Work, Post } from '../services/api'
|
||||
import { useScrollAnimation } from '../composables/useScrollAnimation'
|
||||
|
||||
const { initObserver } = useScrollAnimation()
|
||||
|
||||
const latestWork = ref<Work>({
|
||||
id: 'nova',
|
||||
title: 'Nova 交易平台',
|
||||
@@ -137,15 +139,16 @@ const fetchHomeData = async () => {
|
||||
loading.value = true
|
||||
error.value = ''
|
||||
try {
|
||||
// 获取最新作品
|
||||
const works = await fetchWorks()
|
||||
if (works.length > 0) {
|
||||
const [works, posts] = await Promise.all([
|
||||
fetchWorks(),
|
||||
fetchPosts()
|
||||
])
|
||||
|
||||
if (works && works.length > 0) {
|
||||
latestWork.value = works[0]
|
||||
}
|
||||
|
||||
// 获取精选文章
|
||||
const posts = await fetchPosts()
|
||||
if (posts.length > 0) {
|
||||
if (posts && posts.length > 0) {
|
||||
featuredPost.value = posts[0]
|
||||
}
|
||||
} catch (err) {
|
||||
@@ -153,15 +156,12 @@ const fetchHomeData = async () => {
|
||||
error.value = '获取首页数据失败'
|
||||
} finally {
|
||||
loading.value = false
|
||||
// 启用滚动动画
|
||||
initObserver()
|
||||
}
|
||||
}
|
||||
|
||||
onBeforeMount(() => {
|
||||
onMounted(() => {
|
||||
fetchHomeData()
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
// 启用滚动动画
|
||||
useScrollAnimation()
|
||||
})
|
||||
</script>
|
||||
@@ -246,9 +246,11 @@ onBeforeMount(() => {
|
||||
fetchServicesData()
|
||||
})
|
||||
|
||||
const { initObserver } = useScrollAnimation()
|
||||
|
||||
onMounted(() => {
|
||||
// 启用滚动动画
|
||||
useScrollAnimation()
|
||||
initObserver()
|
||||
|
||||
// 初始化Lucide图标
|
||||
if (window.lucide) {
|
||||
|
||||
@@ -52,12 +52,16 @@ const snippets = ref<Snippet[]>([])
|
||||
const loading = ref(false)
|
||||
const error = ref('')
|
||||
|
||||
const { initObserver } = useScrollAnimation()
|
||||
|
||||
const fetchSnippetsData = async () => {
|
||||
loading.value = true
|
||||
error.value = ''
|
||||
try {
|
||||
const snippetsData = await fetchSnippets()
|
||||
snippets.value = snippetsData
|
||||
// 初始化动画 - 在数据加载完成后
|
||||
initObserver()
|
||||
} catch (err) {
|
||||
console.error('Error fetching snippets:', err)
|
||||
error.value = '获取代码片段失败,请稍后重试'
|
||||
@@ -111,6 +115,8 @@ export const useMousePosition = () => {
|
||||
type: 'animate'
|
||||
}
|
||||
]
|
||||
// 静态数据加载后也要初始化动画
|
||||
initObserver()
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
@@ -136,14 +142,8 @@ const openSnippet = (snippet: any) => {
|
||||
}
|
||||
}
|
||||
|
||||
onBeforeMount(() => {
|
||||
fetchSnippetsData()
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
// 启用滚动动画
|
||||
useScrollAnimation()
|
||||
|
||||
fetchSnippetsData()
|
||||
// 初始化Lucide图标
|
||||
if (window.lucide) {
|
||||
window.lucide.createIcons()
|
||||
|
||||
@@ -124,6 +124,8 @@ const work = ref<Work>({
|
||||
const loading = ref(true)
|
||||
const error = ref('')
|
||||
|
||||
const { initObserver } = useScrollAnimation()
|
||||
|
||||
const updateScrollProgress = () => {
|
||||
const scrollTop = window.scrollY
|
||||
const docHeight = document.documentElement.scrollHeight
|
||||
@@ -142,6 +144,8 @@ const fetchWorkDetails = async () => {
|
||||
const workData = await fetchWork(workId)
|
||||
if (workData) {
|
||||
work.value = workData
|
||||
// 初始化动画 - 在数据加载完成后
|
||||
initObserver()
|
||||
} else {
|
||||
error.value = '未找到该作品'
|
||||
}
|
||||
@@ -154,9 +158,6 @@ const fetchWorkDetails = async () => {
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
// 启用滚动动画
|
||||
useScrollAnimation()
|
||||
|
||||
fetchWorkDetails()
|
||||
// 初始化Lucide图标
|
||||
if (window.lucide) {
|
||||
|
||||
@@ -90,11 +90,15 @@ const works = ref<Work[]>([])
|
||||
const loading = ref(false)
|
||||
const error = ref('')
|
||||
|
||||
const { initObserver } = useScrollAnimation()
|
||||
|
||||
const fetchWorksData = async () => {
|
||||
loading.value = true
|
||||
error.value = ''
|
||||
try {
|
||||
works.value = await fetchWorks()
|
||||
// 初始化动画 - 在数据加载完成后
|
||||
initObserver()
|
||||
} catch (err) {
|
||||
error.value = '获取作品失败,请稍后重试'
|
||||
console.error('Error fetching works:', err)
|
||||
@@ -104,9 +108,6 @@ const fetchWorksData = async () => {
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
// 启用滚动动画
|
||||
useScrollAnimation()
|
||||
|
||||
fetchWorksData()
|
||||
// 初始化Lucide图标
|
||||
if (window.lucide) {
|
||||
|
||||
Reference in New Issue
Block a user