feat:文章页新增面包屑

This commit is contained in:
Xwen
2023-12-17 11:57:46 +08:00
parent 0d5e993042
commit 72307cd89f
7 changed files with 172 additions and 14 deletions

View File

@@ -18,6 +18,7 @@
"marked": "^4.2.12", "marked": "^4.2.12",
"mavon-editor": "^3.0.0", "mavon-editor": "^3.0.0",
"nprogress": "^0.2.0", "nprogress": "^0.2.0",
"path-to-regexp": "^6.2.1",
"pinia": "^2.0.32", "pinia": "^2.0.32",
"pinia-plugin-persistedstate": "^3.2.0", "pinia-plugin-persistedstate": "^3.2.0",
"vue": "^3.2.47", "vue": "^3.2.47",
@@ -2851,6 +2852,11 @@
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
"dev": true "dev": true
}, },
"node_modules/path-to-regexp": {
"version": "6.2.1",
"resolved": "https://registry.npmmirror.com/path-to-regexp/-/path-to-regexp-6.2.1.tgz",
"integrity": "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw=="
},
"node_modules/path-type": { "node_modules/path-type": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmmirror.com/path-type/-/path-type-4.0.0.tgz", "resolved": "https://registry.npmmirror.com/path-type/-/path-type-4.0.0.tgz",
@@ -6087,6 +6093,11 @@
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
"dev": true "dev": true
}, },
"path-to-regexp": {
"version": "6.2.1",
"resolved": "https://registry.npmmirror.com/path-to-regexp/-/path-to-regexp-6.2.1.tgz",
"integrity": "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw=="
},
"path-type": { "path-type": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmmirror.com/path-type/-/path-type-4.0.0.tgz", "resolved": "https://registry.npmmirror.com/path-type/-/path-type-4.0.0.tgz",

View File

@@ -18,6 +18,7 @@
"marked": "^4.2.12", "marked": "^4.2.12",
"mavon-editor": "^3.0.0", "mavon-editor": "^3.0.0",
"nprogress": "^0.2.0", "nprogress": "^0.2.0",
"path-to-regexp": "^6.2.1",
"pinia": "^2.0.32", "pinia": "^2.0.32",
"pinia-plugin-persistedstate": "^3.2.0", "pinia-plugin-persistedstate": "^3.2.0",
"vue": "^3.2.47", "vue": "^3.2.47",

View File

@@ -0,0 +1,84 @@
<template>
<el-breadcrumb class="app-breadcrumb">
<el-breadcrumb-item v-for="(item, index) in breadcrumbs" :key="item.path">
<span
v-if="
item.redirect === 'noRedirect' || index === breadcrumbs.length - 1
"
class="no-redirect"
>
{{ item.meta.title }}
</span>
<a v-else @click.prevent="handleLink(item)">
{{ item.meta.title }}
</a>
</el-breadcrumb-item>
</el-breadcrumb>
</template>
<script setup>
import { ref, watch, defineProps } from "vue";
import { useRoute, useRouter } from "vue-router";
import { compile } from "path-to-regexp";
const props = defineProps({
// 面包屑列表
breadcrumbsList: {
type: Array,
default: () => [],
},
});
const route = useRoute();
const router = useRouter();
const breadcrumbs = ref([]);
const getBreadcrumb = () => {
breadcrumbs.value = props.breadcrumbsList;
};
const pathCompile = (path) => {
const { params } = route;
const toPath = compile(path);
return toPath(params);
};
const handleLink = (item) => {
const { redirect, path } = item;
if (redirect) {
router.push(redirect);
return;
}
router.push(pathCompile(path));
};
watch(
() => route.path,
(path) => {
if (path.startsWith("/redirect/")) {
return;
}
getBreadcrumb();
}
);
getBreadcrumb();
</script>
<style lang="scss" scoped>
.el-breadcrumb__inner,
.el-breadcrumb__inner a {
font-weight: 400 !important;
}
.app-breadcrumb.el-breadcrumb {
display: inline-block;
font-size: 14px;
line-height: var(--v3-navigationbar-height);
margin-left: 8px;
.no-redirect {
color: #97a8be;
cursor: text;
}
}
</style>

View File

@@ -14,15 +14,16 @@ import directive from "./directive"; // directive
import "./permission"; import "./permission";
const app = createApp(App); (async () => {
for (const [key, component] of Object.entries(ElementPlusIconsVue)) { const app = createApp(App);
app.component(key, component); for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
} app.component(key, component);
}
const pinia = createPinia(); const pinia = createPinia();
pinia.use(piniaPluginPersistedstate); pinia.use(piniaPluginPersistedstate);
app.use(pinia);
app.use(pinia); directive(app);
directive(app); app.use(router);
app.use(router); await router.isReady();
app.mount("#app"); app.mount("#app");
})();

View File

@@ -42,6 +42,9 @@ const router = createRouter({
name: "index", name: "index",
path: "/index", path: "/index",
component: () => import("../views/home/Index.vue"), component: () => import("../views/home/Index.vue"),
meta: {
title: "首页",
},
}, },
{ {
name: "article", name: "article",
@@ -52,6 +55,9 @@ const router = createRouter({
name: "discuss", name: "discuss",
path: "/discuss/:plateId?", path: "/discuss/:plateId?",
component: () => import("../views/Discuss.vue"), component: () => import("../views/Discuss.vue"),
meta: {
title: "板块",
},
}, },
{ {
//artTypediscuss主题、article文章 //artTypediscuss主题、article文章
@@ -65,6 +71,14 @@ const router = createRouter({
path: "/profile", path: "/profile",
component: () => import("../views/profile/Index.vue"), component: () => import("../views/profile/Index.vue"),
}, },
{
name: "themeCover",
path: "/article/:discussId",
component: () => import("../views/Article.vue"),
meta: {
title: "主题封面",
},
},
], ],
}, },
{ path: "/:pathMatch(.*)*", name: "NotFound", component: NotFound }, { path: "/:pathMatch(.*)*", name: "NotFound", component: NotFound },

View File

@@ -10,7 +10,7 @@
<el-button <el-button
style="width: 100%; margin-bottom: 0.8rem" style="width: 100%; margin-bottom: 0.8rem"
@click="loadDiscuss(true)" @click="loadDiscuss(true)"
>首页</el-button >主题封面</el-button
> >
<el-button <el-button
v-hasPer="['bbs:article:add']" v-hasPer="['bbs:article:add']"
@@ -51,6 +51,7 @@
<el-col :span="14"> <el-col :span="14">
<el-row class="left-div"> <el-row class="left-div">
<el-col :span="24"> <el-col :span="24">
<Breadcrumb :breadcrumbsList="breadcrumbsList" class="breadcrumb" />
<!-- {{ discuss.user }} --> <!-- {{ discuss.user }} -->
<AvatarInfo <AvatarInfo
:size="50" :size="50"
@@ -170,7 +171,7 @@
</div> </div>
</template> </template>
<script setup> <script setup>
import { h, ref, onMounted } from "vue"; import { h, ref, onMounted, watch } from "vue";
import AvatarInfo from "@/components/AvatarInfo.vue"; import AvatarInfo from "@/components/AvatarInfo.vue";
import InfoCard from "@/components/InfoCard.vue"; import InfoCard from "@/components/InfoCard.vue";
import ArticleContentInfo from "@/components/ArticleContentInfo.vue"; import ArticleContentInfo from "@/components/ArticleContentInfo.vue";
@@ -185,6 +186,8 @@ import {
del as articleDel, del as articleDel,
get as articleGet, get as articleGet,
} from "@/apis/articleApi.js"; } from "@/apis/articleApi.js";
import Breadcrumb from "@/components/Breadcrumb/index.vue";
//数据定义 //数据定义
const route = useRoute(); const route = useRoute();
const router = useRouter(); const router = useRouter();
@@ -205,6 +208,11 @@ const currentNodeKey = route.params.articleId;
//目录数据 //目录数据
const catalogueData = ref([]); const catalogueData = ref([]);
// 面包屑导航列表
const breadcrumbsList = ref([]);
// 当前文章名称
const currentArticle = ref("");
//子文章初始化 //子文章初始化
const loadArticleData = async () => { const loadArticleData = async () => {
const response = await articleall(route.params.discussId); const response = await articleall(route.params.discussId);
@@ -315,6 +323,7 @@ const updateArticle = (node, data) => {
}; };
//单机节点 //单机节点
const handleNodeClick = async (data) => { const handleNodeClick = async (data) => {
currentArticle.value = data?.name;
//跳转路由 //跳转路由
router.push(`/article/${route.params.discussId}/${data.id}`); router.push(`/article/${route.params.discussId}/${data.id}`);
@@ -343,6 +352,35 @@ onMounted(async () => {
await loadDiscuss(); await loadDiscuss();
await loadArticleData(); await loadArticleData();
}); });
const resultRouters = ["index", "discuss", "themeCover"];
breadcrumbsList.value = route.matched[0].children
.filter((item) => resultRouters.includes(item.name))
.sort((a, b) => {
return resultRouters.indexOf(a.name) - resultRouters.indexOf(b.name);
});
watch(
() => currentArticle.value,
(val) => {
if (val !== "") {
breadcrumbsList.value[3] = {
name: "article",
path: "/article/:discussId",
meta: {
title: currentArticle.value,
},
};
}
}
);
watch(
() => route.params.articleId,
async (val) => {
if (val === "") {
discuss.value = (await discussGet(route.params.discussId)).data;
}
}
);
</script> </script>
<style scoped> <style scoped>
.comment { .comment {
@@ -425,4 +463,8 @@ h2 {
.tab-divider { .tab-divider {
margin-bottom: 0.5rem; margin-bottom: 0.5rem;
} }
.breadcrumb {
margin-bottom: 10px;
}
</style> </style>

View File

@@ -1642,6 +1642,11 @@
"resolved" "https://registry.npmmirror.com/path-parse/-/path-parse-1.0.7.tgz" "resolved" "https://registry.npmmirror.com/path-parse/-/path-parse-1.0.7.tgz"
"version" "1.0.7" "version" "1.0.7"
"path-to-regexp@^6.2.1":
"integrity" "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw=="
"resolved" "https://registry.npmmirror.com/path-to-regexp/-/path-to-regexp-6.2.1.tgz"
"version" "6.2.1"
"path-type@^4.0.0": "path-type@^4.0.0":
"integrity" "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" "integrity" "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw=="
"resolved" "https://registry.npmmirror.com/path-type/-/path-type-4.0.0.tgz" "resolved" "https://registry.npmmirror.com/path-type/-/path-type-4.0.0.tgz"