feat: 添加博客分类和分页功能

为博客页面添加分类筛选功能,支持按分类查看文章
实现分页功能,优化文章列表展示
调整页面布局和样式,增加交互效果
This commit is contained in:
2026-01-01 16:43:18 +08:00
parent a9d3854a55
commit e924fcca2b
8 changed files with 91 additions and 19 deletions

1
components.d.ts vendored
View File

@ -37,6 +37,7 @@ declare module 'vue' {
NMessageProvider: typeof import('naive-ui')['NMessageProvider']
NModal: typeof import('naive-ui')['NModal']
NModalProvider: typeof import('naive-ui')['NModalProvider']
NPagination: typeof import('naive-ui')['NPagination']
NScrollbar: typeof import('naive-ui')['NScrollbar']
NSelect: typeof import('naive-ui')['NSelect']
NTabPane: typeof import('naive-ui')['NTabPane']

View File

@ -5,7 +5,7 @@
<meta charset="UTF-8">
<link rel="icon" href="/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="这是柚子的网站,做一些分享类的功能"/>
<meta name="description" content="这是柚子的网站,做一些分享类的功能"/>
<title>柚子の网站</title>
</head>
@ -17,8 +17,6 @@
<script type="text/javascript">
! function (e, t, a) {
function r() {
for (var e = 0; e < s.length; e++) s[e].alpha <= 0 ? (t.body.removeChild(s[e].el), s.splice(e, 1)) : (s[
e].y--, s[e].scale += .004, s[e].alpha -= .013, s[e].el.style.cssText = "left:" + s[e].x +

View File

@ -32,6 +32,7 @@
</n-modal>
<back-top />
</template>
<script setup lang="ts">

View File

@ -1,10 +1,11 @@
import request from "@/util/request";
//getBlogList
export function getBlogList() {
export function getBlogList(params: any) {
return request({
url: "/art",
method: "get",
params
});
}
//getBlogDetail
@ -14,3 +15,10 @@ export function getBlogDetail(id: string) {
method: "get",
});
}
//getCateList
export function getCateList() {
return request({
url: `/art/category`,
method: "get",
});
}

View File

@ -1,7 +1,7 @@
<template>
<div ref="nav" class="main-nav hidden lg:flex justify-between bg-white">
<!-- 网站Logo -->
<div class="px-5 items-centerflex" slot="brand" @click="goHome">
<div class="px-5 items-centerflex cursor-pointer" slot="brand" @click="goHome">
<img :src="logo" alt="柚子的网站" class="h-9 align-middle" />
</div>
<!-- 主导航菜单 -->
@ -9,7 +9,7 @@
<n-menu :icon-size="12" v-model:value="activeKey" class="" mode="horizontal" :options="menuOptions" />
</div>
<!-- 用户区域 -->
<div class="!text-[#ec66ab] flex items-center" @click="gotoHf">
<div class="!text-[#ec66ab] flex items-center cursor-pointer" @click="gotoHf">
<span class="flex items-center location-info truncate">
<n-icon class="mr-1">
<icon-loc class="w-[26px] h-[26px]"></icon-loc>
@ -81,11 +81,11 @@
// 从@/icon/menu引入所有的svg文件
import logo from '@/assets/images/logo.png';
import artiSvg from '@/icon/menu/arti.svg';
import downSvg from '@/icon/menu/download.svg';
// import downSvg from '@/icon/menu/download.svg';
import homeSvg from '@/icon/menu/home.svg';
import linkSvg from '@/icon/menu/link.svg';
import picSvg from '@/icon/menu/pic.svg';
import settingSvg from '@/icon/menu/setting.svg';
// import settingSvg from '@/icon/menu/setting.svg';
import loginModal from '@/components/Login.vue'
import masked from '@/components/mask.vue'
import type { UploadFileInfo } from 'naive-ui'

1
src/icon/arti.svg Normal file
View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1767254162122" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5014" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M661.648 118H249.104c-39.088 0-70.304 31.752-70.304 70.304v647.392c0 39.096 31.752 70.304 70.304 70.304h525.8c38.552 0 70.296-31.752 70.296-70.304V301.56L661.648 118z m12.664 74.704l96.176 96.184H684.584c-5.408 0-10.272-4.864-10.272-10.272V192.704z m126.928 642.992a26.24 26.24 0 0 1-26.344 26.352H249.104a26.24 26.24 0 0 1-26.344-26.352V188.304a26.24 26.24 0 0 1 26.344-26.344v-0.464h381.328v117.192c0 29.824 24.416 54.16 54.16 54.16h116.656v502.848z" p-id="5015"></path><path d="M348.68 386.072h188.968a21.84 21.84 0 0 0 21.944-21.936 21.84 21.84 0 0 0-21.944-21.944H348.68a21.832 21.832 0 0 0-21.944 21.944 21.84 21.84 0 0 0 21.944 21.936zM674.848 644.8H348.68c-12.208 0-21.944 9.744-21.944 21.944s9.736 21.944 21.944 21.944h326.168c12.208 0 21.944-9.744 21.944-21.944S687.064 644.8 674.848 644.8zM348.68 495.856a21.824 21.824 0 0 0-21.944 21.944 21.832 21.832 0 0 0 21.944 21.936h326.168a21.832 21.832 0 0 0 21.944-21.936 21.832 21.832 0 0 0-21.944-21.944H348.68z" p-id="5016"></path></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -25,7 +25,6 @@
</div>
</div>
</div>
<back-top />
</template>
<script setup lang="ts">

View File

@ -1,10 +1,24 @@
<template>
<div class="article-page w-full flex" :style="boxStyle">
<div class="w-1/4 shadow">
<div class="w-1/4 shadow relative">
<div class="card w-2/3 absolute top-16 left-1/6">
<div @click="clickCate(i, idx)" v-for="(i, idx) in cateList" :key="i.cid"
:class="{ '!bg-primary text-white': idx == currentCateIdx }"
class="relative cate my-4 py-8 px-16 text-center text-xl font-bold rounded text-gray-600 bg-gray-200 cursor-pointer">
{{ i.name }}
<div class="absolute bottom-1 right-4 ext-sm text-deepp flex items-center gap-2">
<icon-arti class="w-4 h-4 !fill-deepp"></icon-arti>
{{ i.total || 0 }}篇文章
</div>
<div class="blog-list w-3/4 pl-16">
<div v-for="item in blogList" :key="item.aid" class="rounded-lg p-4 w-3/4 my-8 shadow cursor-pointer"
</div>
</div>
</div>
<div class="blog-list w-3/4 mt-10">
<div v-show="blogList.length == 0" class="ml-50 text-gray-500 mt-20">
什么都没有呢~ ~
</div>
<div v-for="item in blogList" :key="item.aid" class="rounded-lg p-4 w-[80%] ml-1/10 my-8 shadow cursor-pointer"
@click="$router.push(`/blog/${item.aid}`)">
<div class="flex justify-right gap-4 mb-2 text-gray-600">
<em class="flex items-center gap-1 text-sm">
@ -19,7 +33,7 @@
<n-icon><icon-author /></n-icon>
{{ item.nickname }}</em>
</div>
<div class="text-xl text-bold text-primary mb-2">{{ item.title }}</div>
<div class="text-xl font-bold text-primary mb-2">{{ item.title }}</div>
<div class="text-sm text-gray-500 mb-4 line-clamp-3">{{ item.pro }}</div>
<div class="flex gap-4">
<div v-for="i in getTags(item.tags)" :key="i.tid" class="flex items-center gap-1 text-deepp cursor-pointer">
@ -27,6 +41,9 @@
</div>
</div>
</div>
<div class="mt-20 w-[80%] ml-1/10 cursor-pointer flex justify-center">
<n-pagination v-model:page="page_num" :page-count="total" :page-slot="5" @update:page="getBlogList" />
</div>
</div>
</div>
</template>
@ -42,9 +59,31 @@ definePage({
const blogList = ref<any[]>([])
const boxStyle = ref({})
const nav: any = $store.nav.useNavStore()
const cateList = ref<any[]>([])
const currentCateIdx = ref(-1)
const page_size = ref(5)
const page_num = ref(1)
const total = ref(0)
const category = ref('')
function clickCate(item: any, idx: number) {
if (currentCateIdx.value == idx) {
currentCateIdx.value = -1
category.value = ''
getBlogList()
total.value = cateList.value.reduce((acc: any, cur: any) => acc + cur.total, 0)
return
}
currentCateIdx.value = idx
category.value = item.cid
getBlogList()
total.value = item.total
console.log('>>> --> clickCate --> total.value:', total.value)
}
async function getBlogList() {
const res = await $http.blog.getBlogList()
console.log('>>> --> getBlogList --> res:', res.data)
const res = await $http.blog.getBlogList({
category:category.value,page_size:page_size.value,page_num:page_num.value
})
blogList.value = res.data
}
// 计算markdown的文字数量
@ -61,17 +100,42 @@ function getTags(str: any) {
});
return tags
}
async function getCateList() {
const res = await $http.blog.getCateList()
console.log('>>> --> getCateList --> res:', res.data)
cateList.value = res.data
total.value = cateList.value.reduce((acc: any, cur: any) => acc + cur.total, 0)
}
onMounted(() => {
boxStyle.value = {
height: `calc(100vh - ${nav.navH + 1}px)`,
}
getBlogList()
getCateList()
})
</script>
<style scoped>
/* 文章页样式 */
@keyframes fangda {
0% {
transform: scale(1);
}
50% {
transform: scale(1.1);
}
100% {
transform: scale(1);
}
}
.cate:hover {
animation: fangda 01s ease-in-out 1;
}
</style>