BlogHome.vue 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. <script setup lang="ts">
  2. import Date from './Date.vue'
  3. import Author from './Author.vue'
  4. import { data as posts } from './posts.data.js'
  5. import { useData } from 'vitepress'
  6. import { computed, ref } from 'vue'
  7. const { frontmatter } = useData()
  8. // 分页配置
  9. const postsPerPage = 10
  10. const currentPage = ref(1)
  11. // 计算分页数据
  12. const paginatedPosts = computed(() => {
  13. const start = (currentPage.value - 1) * postsPerPage
  14. const end = start + postsPerPage
  15. return posts.slice(start, end)
  16. })
  17. const totalPages = computed(() => Math.ceil(posts.length / postsPerPage))
  18. // 分页导航
  19. const goToPage = (page: number) => {
  20. if (page >= 1 && page <= totalPages.value) {
  21. currentPage.value = page
  22. window.scrollTo({ top: 0, behavior: 'smooth' })
  23. }
  24. }
  25. const goToPrevPage = () => goToPage(currentPage.value - 1)
  26. const goToNextPage = () => goToPage(currentPage.value + 1)
  27. </script>
  28. <template>
  29. <div class="divide-y divide-gray-200 dark:divide-slate-200/5">
  30. <div class="pt-6 pb-8 space-y-2 md:space-y-5">
  31. <h1
  32. class="text-3xl leading-9 font-extrabold text-gray-900 dark:text-white tracking-tight sm:text-4xl sm:leading-10 md:text-6xl md:leading-14"
  33. >
  34. {{ frontmatter.title }}
  35. </h1>
  36. <p class="text-lg leading-7 text-gray-500 dark:text-gray-300">
  37. {{ frontmatter.subtext }}
  38. </p>
  39. </div>
  40. <ul class="divide-y divide-gray-200 dark:divide-slate-200/5">
  41. <li class="py-12" v-for="{ title, url, date, excerpt, author } of paginatedPosts">
  42. <article
  43. class="space-y-2 xl:grid xl:grid-cols-4 xl:space-y-0 xl:items-baseline"
  44. >
  45. <Date :date="date" />
  46. <div class="space-y-5 xl:col-span-3">
  47. <div class="space-y-6">
  48. <h2 class="text-2xl leading-8 font-bold tracking-tight">
  49. <a class="text-gray-900 dark:text-white hover:text-gray-600 dark:hover:text-gray-300" :href="url">{{
  50. title
  51. }}</a>
  52. </h2>
  53. <Author :author="author" />
  54. <div
  55. v-if="excerpt"
  56. class="prose dark:prose-invert max-w-none text-gray-500 dark:text-gray-300"
  57. v-html="excerpt"
  58. ></div>
  59. </div>
  60. <div class="text-base leading-6 font-medium">
  61. <a class="link hover:text-gray-600 dark:hover:text-gray-300" aria-label="read more" :href="url">Read more →</a>
  62. </div>
  63. </div>
  64. </article>
  65. </li>
  66. </ul>
  67. <!-- 分页导航 -->
  68. <div v-if="totalPages > 1" class="flex justify-center items-center space-x-4 py-8">
  69. <button
  70. @click="goToPrevPage"
  71. :disabled="currentPage === 1"
  72. class="px-4 py-2 text-sm font-medium text-gray-500 bg-white border border-gray-300 rounded-md hover:bg-gray-50 disabled:opacity-50 disabled:cursor-not-allowed dark:bg-gray-800 dark:border-gray-600 dark:text-gray-300 dark:hover:bg-gray-700"
  73. >
  74. Previous
  75. </button>
  76. <span class="text-sm text-gray-500 dark:text-gray-400">
  77. Page {{ currentPage }} of {{ totalPages }}
  78. </span>
  79. <button
  80. @click="goToNextPage"
  81. :disabled="currentPage === totalPages"
  82. class="px-4 py-2 text-sm font-medium text-gray-500 bg-white border border-gray-300 rounded-md hover:bg-gray-50 disabled:opacity-50 disabled:cursor-not-allowed dark:bg-gray-800 dark:border-gray-600 dark:text-gray-300 dark:hover:bg-gray-700"
  83. >
  84. Next
  85. </button>
  86. </div>
  87. </div>
  88. </template>
  89. <style scoped>
  90. .link {
  91. @apply text-blue-600 dark:text-blue-400;
  92. }
  93. </style>