ソースを参照

feat(路由): 添加博文详情页路由并实现导航功能

- 在路由配置中添加详情页路由
- 修改PostCard组件实现点击标题跳转到详情页
- 调整PostDetailView获取参数逻辑,从query改为params
- 优化详情页错误处理和导航逻辑
- 移除PostDetailContent中多余的class
- 整理main.css媒体查询代码结构
Sakulin 2 ヶ月 前
コミット
1b6e769552

+ 71 - 70
src/assets/main.css

@@ -130,76 +130,6 @@ a {
     border-radius: 12px;
 }
 
-@media screen and (max-width: 800px) {
-    .container {
-        flex-direction: column;
-        align-items: center;
-        padding: 0;
-    }
-
-    .aside {
-        box-sizing: border-box;
-        width: 100%;
-        display: flex;
-        flex-direction: row;
-        gap: 10px;
-        position: sticky;
-        top: 0;
-        left: 0;
-        z-index: 100;
-        border-radius: 0;
-    }
-
-    .aside .avatar-box {
-        flex-direction: row;
-        gap: 10px;
-        margin: 0;
-        padding: 5px;
-    }
-
-    .aside .avatar-box .avatar {
-        width: 50px;
-        height: 50px;
-        margin: 0;
-    }
-
-    .aside .avatar-box .info {
-        align-items: flex-start;
-    }
-
-    .aside .avatar-box .desc {
-        max-width: 100px;
-        white-space: nowrap;
-        overflow: hidden;
-        text-overflow: ellipsis;
-    }
-
-    .aside .nav {
-        flex-direction: row;
-        gap: 5px;
-        overflow-y: hidden;
-        overflow-x: auto;
-        white-space: nowrap;
-    }
-
-    .aside .nav a {
-        line-height: 50px;
-    }
-
-    .main {
-        width: 100%;
-    }
-
-    .post-item {
-        border-radius: 0;
-    }
-
-    .footer {
-        border-radius: 0;
-    }
-
-}
-
 
 .post-item p,
 .post-item img,
@@ -267,3 +197,74 @@ a {
   content: '·';
   margin: 0 5px;
 }
+
+
+@media screen and (max-width: 800px) {
+  .container {
+    flex-direction: column;
+    align-items: center;
+    padding: 0;
+  }
+
+  .aside {
+    box-sizing: border-box;
+    width: 100%;
+    display: flex;
+    flex-direction: row;
+    gap: 10px;
+    position: sticky;
+    top: 0;
+    left: 0;
+    z-index: 100;
+    border-radius: 0;
+  }
+
+  .aside .avatar-box {
+    flex-direction: row;
+    gap: 10px;
+    margin: 0;
+    padding: 5px;
+  }
+
+  .aside .avatar-box .avatar {
+    width: 50px;
+    height: 50px;
+    margin: 0;
+  }
+
+  .aside .avatar-box .info {
+    align-items: flex-start;
+  }
+
+  .aside .avatar-box .desc {
+    max-width: 100px;
+    white-space: nowrap;
+    overflow: hidden;
+    text-overflow: ellipsis;
+  }
+
+  .aside .nav {
+    flex-direction: row;
+    gap: 5px;
+    overflow-y: hidden;
+    overflow-x: auto;
+    white-space: nowrap;
+  }
+
+  .aside .nav a {
+    line-height: 50px;
+  }
+
+  .main {
+    width: 100%;
+  }
+
+  .post-item {
+    border-radius: 0;
+  }
+
+  .footer {
+    border-radius: 0;
+  }
+
+}

+ 14 - 5
src/components/PostCard.vue

@@ -2,17 +2,25 @@
 import type { PostSketch } from '@/models'
 import TagCloud from './TagCloud.vue'
 import { formateDateAccurateToDay } from '@/utils'
+import { router } from '@/router'
 
 const props = defineProps<{
   target: PostSketch
-}>();
-
+}>()
 
+function handleRouteToDetail() {
+  router.push({
+    name: 'detail',
+    query: {
+      id: props.target.id,
+    },
+  })
+}
 </script>
 
 <template>
   <div class="post-item">
-    <h2 class="title">{{ props.target.title }}</h2>
+    <h2 class="title" @click="handleRouteToDetail">{{ props.target.title }}</h2>
     <div class="meta">
       <span class="date">{{ formateDateAccurateToDay(props.target.createdAt) }}</span>
       <span class="cate">日志</span>
@@ -25,6 +33,7 @@ const props = defineProps<{
 </template>
 
 <style scoped>
-
-
+.post-item .title {
+  cursor: pointer;
+}
 </style>

+ 1 - 1
src/components/PostDetailContent.vue

@@ -8,7 +8,7 @@ const props = defineProps<{
 </script>
 
 <template>
-  <div class="post-list">
+  <div>
     <div class="post-item">
       <h1 class="title">{{ props.target.title }}</h1>
       <div class="meta">

+ 7 - 0
src/router/index.ts

@@ -45,6 +45,13 @@ export const modules: BlogModule[] = [
     component: () => import('../views/FriendLinkView.vue'),
     showInMenu: true
   },
+  {
+    routeName: "detail",
+    title: "博文详情",
+    routeUrl: "/detail",
+    component: () => import('../views/PostDetailView.vue'),
+    showInMenu: false
+  }
 ];
 
 function toRouteRecordRaw(target: BlogModule): RouteRecordRaw {

+ 1 - 1
src/utils/axios.ts

@@ -32,7 +32,7 @@ export const api = {
   postList(length: number = 10, start: number = 10) {
     return baseServer.get(`/post/list?length=${length}&start=${start}`).then(res => res.data) as Promise<PostListSuccess>
   },
-  postGet(id: number = 2) {
+  postGet(id: number) {
     return baseServer.get(`/post/get/${id}`).then(res => res.data) as Promise<PostGetSuccess | DefaultFailedResponse>
   },
   tagList() {

+ 11 - 3
src/views/PostDetailView.vue

@@ -6,12 +6,14 @@ import type { PostDetail } from '@/models'
 import PostDetailContent from '@/components/PostDetailContent.vue'
 
 function parseId() {
-  let targetPostId = router.currentRoute.value.params['id']
+  console.log(router.currentRoute.value.params) // 为什么输出为空
+  let targetPostId = router.currentRoute.value.query['id']
   if (Array.isArray(targetPostId)) {
     if (targetPostId.length) {
       targetPostId = targetPostId[0]
     } else return undefined
   }
+  if (!targetPostId) return undefined;
   const id = Number(targetPostId)
   if (isNaN(id)) {
     return undefined
@@ -28,15 +30,21 @@ async function freshData() {
   if (res.code == 200) {
     postDetail.value = res.data
     return true
-  } else return false
+  } else {
+    console.error(res.msg)
+    return false
+  }
 }
 
 onMounted(() => {
   postId = parseId() ?? NaN
-  if (!postId) {
+  if (isNaN(postId)) {
     router.push('/')
+    return;
   }
 
+  console.log(postId)
+
   freshData().then((res) => {
     if (!res) router.push('/')
   })