初始化
This commit is contained in:
115
client/src/pages/BlogDetail.vue
Normal file
115
client/src/pages/BlogDetail.vue
Normal file
@@ -0,0 +1,115 @@
|
||||
<template>
|
||||
<section id="blog-detail" class="page-section block animate-slide-down">
|
||||
<div class="max-w-4xl mx-auto pt-32 px-6 pb-20">
|
||||
<!-- 返回按钮 -->
|
||||
<button
|
||||
@click="$router.push('/blog')"
|
||||
class="group flex items-center gap-2 text-art-muted hover:text-white transition-colors mb-12"
|
||||
>
|
||||
<i data-lucide="arrow-left" class="w-4 h-4 transform group-hover:-translate-x-1 transition-transform"></i>
|
||||
<span class="text-sm font-medium tracking-wide">返回文章列表</span>
|
||||
</button>
|
||||
|
||||
<!-- Loading state -->
|
||||
<div v-if="loading" class="flex justify-center items-center h-64">
|
||||
<div class="animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-art-accent"></div>
|
||||
</div>
|
||||
|
||||
<!-- Error state -->
|
||||
<div v-else-if="error" class="text-center text-red-500 py-20">
|
||||
<p class="mb-4">{{ error }}</p>
|
||||
<button @click="fetchBlogDetail" class="px-4 py-2 bg-art-accent text-white rounded hover:bg-opacity-80 transition-colors">
|
||||
重试
|
||||
</button>
|
||||
<button @click="$router.push('/blog')" class="mt-4 px-4 py-2 border border-white/30 text-white rounded hover:bg-white/5 transition-colors">
|
||||
返回文章列表
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Blog detail content -->
|
||||
<div v-else class="space-y-12">
|
||||
<!-- 文章信息 -->
|
||||
<div class="border-b border-white/5 pb-10">
|
||||
<div class="flex items-center gap-4 mb-6">
|
||||
<span class="px-3 py-1 border border-white/20 rounded-full text-xs font-mono text-art-accent uppercase tracking-wider">{{ post.category }}</span>
|
||||
<span class="text-sm text-art-muted">{{ post.date }}</span>
|
||||
</div>
|
||||
<h1 class="font-serif text-4xl md:text-5xl lg:text-6xl text-white leading-tight mb-8">{{ post.title }}</h1>
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="w-10 h-10 rounded-full overflow-hidden border border-white/20">
|
||||
<img
|
||||
src="https://api.dicebear.com/7.x/avataaars/svg?seed=NianGao"
|
||||
alt="Avatar"
|
||||
class="w-full h-full object-cover"
|
||||
>
|
||||
</div>
|
||||
<div>
|
||||
<div class="text-sm font-medium text-white">年糕崽崽</div>
|
||||
<div class="text-xs text-art-muted">前端架构师</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 文章内容 -->
|
||||
<article class="blog-content prose prose-invert prose-lg max-w-none text-art-muted leading-relaxed">
|
||||
<div v-html="post.content"></div>
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, onBeforeMount } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { fetchPost, Post } from '../services/api'
|
||||
import { useScrollAnimation } from '../composables/useScrollAnimation'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const postId = route.params.id as string
|
||||
|
||||
const post = ref<Post>({
|
||||
id: postId,
|
||||
title: '',
|
||||
category: '',
|
||||
date: '',
|
||||
excerpt: '',
|
||||
content: ''
|
||||
})
|
||||
|
||||
const loading = ref(false)
|
||||
const error = ref('')
|
||||
|
||||
const fetchBlogDetail = async () => {
|
||||
loading.value = true
|
||||
error.value = ''
|
||||
try {
|
||||
const postData = await fetchPost(postId)
|
||||
if (postData) {
|
||||
post.value = postData
|
||||
} else {
|
||||
error.value = '未找到该文章'
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Error fetching blog detail:', err)
|
||||
error.value = '获取文章详情失败,请稍后重试'
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onBeforeMount(() => {
|
||||
fetchBlogDetail()
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
// 启用滚动动画
|
||||
useScrollAnimation()
|
||||
|
||||
// 初始化Lucide图标
|
||||
if (window.lucide) {
|
||||
window.lucide.createIcons()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
Reference in New Issue
Block a user