feat: 添加博客分类和分页功能
为博客页面添加分类筛选功能,支持按分类查看文章 实现分页功能,优化文章列表展示 调整页面布局和样式,增加交互效果
This commit is contained in:
1
components.d.ts
vendored
1
components.d.ts
vendored
@ -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']
|
||||
|
||||
@ -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 +
|
||||
|
||||
@ -32,6 +32,7 @@
|
||||
</n-modal>
|
||||
|
||||
|
||||
<back-top />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
||||
@ -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",
|
||||
});
|
||||
}
|
||||
@ -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
1
src/icon/arti.svg
Normal 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 |
@ -25,7 +25,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<back-top />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
||||
@ -1,14 +1,28 @@
|
||||
<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>
|
||||
</div>
|
||||
</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 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">
|
||||
<n-icon><icon-date/></n-icon>
|
||||
<n-icon><icon-date /></n-icon>
|
||||
{{ formatTime(item.updated_at, 'YYYY年MM月DD日') }}
|
||||
</em>
|
||||
<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的文字数量
|
||||
@ -56,22 +95,47 @@ function getSize(str: string) {
|
||||
function getTags(str: any) {
|
||||
str = str.replaceAll(',', ',')
|
||||
let tags = str.split(',').slice(0, 5)
|
||||
tags.forEach((tag:any,idx:number) => {
|
||||
tags.forEach((tag: any, idx: number) => {
|
||||
tags[idx] = tag.trim().slice(0, 3)
|
||||
});
|
||||
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>
|
||||
Reference in New Issue
Block a user