Pārlūkot izejas kodu

feat(组件): 优化文章卡片样式并新增标签卡片组件

- 为PostCard标题添加悬停动画效果
- 提取标签样式为独立组件TagCard
- 重构TagCloud使用新组件
- 改进PostView的加载状态和样式
Sakulin 2 mēneši atpakaļ
vecāks
revīzija
060607334e

+ 11 - 2
src/components/PostCard.vue

@@ -20,7 +20,9 @@ function handleRouteToDetail() {
 
 <template>
   <div class="post-item">
-    <h2 class="title" @click="handleRouteToDetail">{{ props.target.title }}</h2>
+    <h2 class="title" @click="handleRouteToDetail">
+      <span>{{ props.target.title }}</span>
+    </h2>
     <div class="meta">
       <span class="date">{{ formateDateAccurateToDay(props.target.createdAt) }}</span>
       <span class="cate">日志</span>
@@ -33,7 +35,14 @@ function handleRouteToDetail() {
 </template>
 
 <style scoped>
-.post-item .title {
+.title span{
   cursor: pointer;
+  background: linear-gradient(to right, var(--text-color), var(--text-color)) no-repeat left bottom;
+  background-size: 0 2px;
+  transition: all .3s;
+}
+.title span:hover {
+  background-size: 100% 2px;
+  text-shadow: var(--secondary-text-color) 0 0 8px;
 }
 </style>

+ 50 - 0
src/components/TagCard.vue

@@ -0,0 +1,50 @@
+<script setup lang="ts">
+
+import type { Tag } from '@/models'
+import { lightenHexColor } from '@/utils'
+import { computed } from 'vue'
+
+const props = defineProps<{
+  target: Tag,
+  onClick?: () => void
+}>();
+
+const color = computed(() => {
+  if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
+    return lightenHexColor(props.target.color);
+  }
+  return props.target.color;
+})
+
+
+
+</script>
+
+<template>
+  <div
+    class="tag"
+    @click="props.onClick?.call(undefined)"
+  >
+    {{ props.target.name }}
+  </div>
+</template>
+
+<style scoped>
+
+.tag {
+  color: v-bind(color);
+  border: 1px solid;
+  border-radius: 50px;
+  padding: 0 16px;
+  display: inline-block;
+  margin: 3px 6px 3px 0;
+  cursor: pointer;
+  transition: all .2s;
+}
+
+.tag:hover {
+  text-shadow: v-bind(color) 0 0 8px;
+  box-shadow: v-bind(color) 0 0 8px;
+}
+
+</style>

+ 6 - 32
src/components/TagCloud.vue

@@ -1,6 +1,6 @@
 <script setup lang="ts">
 import type { Tag } from '@/models'
-import { lightenHexColor } from '@/utils/'
+import TagCard from '@/components/TagCard.vue'
 
 const props = defineProps<{
   tags: Tag[]
@@ -13,43 +13,17 @@ function handleClick(tag: Tag) {
   }
 }
 
-function getColorStyle(tag: Tag) {
-  let color = tag.color;
-
-  if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
-    color = lightenHexColor(color);
-  }
-
-  return {
-    color: color,
-    borderColor: color,
-  }
-}
 </script>
 
 <template>
   <div>
-    <div
-      class="tag"
+    <TagCard
       v-for="tag in props.tags"
       :key="tag.id"
-      @click="handleClick(tag)"
-      :style="getColorStyle(tag)"
-    >
-      {{ tag.name }}
-    </div>
+      :target="tag"
+      :on-click="() => handleClick(tag)"
+    />
   </div>
 </template>
 
-<style scoped>
-.tag {
-  color: inherit;
-  border: 1px solid;
-  border-radius: 50px;
-  padding: 0 16px;
-  display: inline-block;
-  margin: 3px 0;
-  margin-right: 6px;
-  cursor: pointer;
-}
-</style>
+<style scoped></style>

+ 44 - 22
src/views/PostView.vue

@@ -1,45 +1,67 @@
 <script setup lang="ts">
-import type { PostSketch } from '@/models';
-import { onMounted, ref } from 'vue';
-import { api } from '@/utils/axios';
-import PostCard from '@/components/PostCard.vue';
+import type { PostSketch } from '@/models'
+import { onMounted, ref } from 'vue'
+import { api } from '@/utils/axios'
+import PostCard from '@/components/PostCard.vue'
 
-const data = ref<PostSketch[]>([]);
-const pageSize = 10;
-const isEnd = ref(false);
+const data = ref<PostSketch[]>([])
+const pageSize = 10
+const isEnd = ref(false)
 
 function nextDatum() {
   if (isEnd.value) {
-    return;
+    return
   }
-  api.postList(pageSize, data.value.length).then((res) => {
-    if (res.data.length < pageSize) {
-      isEnd.value = true;
-    }
-    data.value = [...data.value, ...res.data];
-  }).catch((err) => {
-    console.error(err);
-  });
+  api
+    .postList(pageSize, data.value.length)
+    .then((res) => {
+      if (res.data.length < pageSize) {
+        isEnd.value = true
+      }
+      data.value = [...data.value, ...res.data]
+    })
+    .catch((err) => {
+      console.error(err)
+    })
 }
 
 onMounted(() => {
-  nextDatum();
-});
-
+  nextDatum()
+})
 </script>
 
 <template>
   <div>
     <PostCard v-for="item of data" :key="item.id" :target="item" />
-    <div v-if="isEnd">
-      没有更多了
+    <div
+      class="post-item"
+      style="padding: 8px; display: flex; justify-content: center"
+      v-if="isEnd"
+    >
+      <div>没有更多了😭</div>
     </div>
-    <div v-else @click="nextDatum">
+    <div
+      class="post-item show-more"
+      v-else
+      @click="nextDatum"
+    >
       显示更多
     </div>
   </div>
 </template>
 
 <style scoped>
+.show-more {
+  color: var(--secondary-text-color);
+  padding: 8px;
+  display: flex;
+  justify-content: center;
+  cursor: pointer;
+}
+
+.show-more:hover {
+  color: var(--text-color);
+}
+
 
 </style>