feat:文章页新增面包屑
This commit is contained in:
11
Yi.Bbs.Vue3/package-lock.json
generated
11
Yi.Bbs.Vue3/package-lock.json
generated
@@ -18,6 +18,7 @@
|
||||
"marked": "^4.2.12",
|
||||
"mavon-editor": "^3.0.0",
|
||||
"nprogress": "^0.2.0",
|
||||
"path-to-regexp": "^6.2.1",
|
||||
"pinia": "^2.0.32",
|
||||
"pinia-plugin-persistedstate": "^3.2.0",
|
||||
"vue": "^3.2.47",
|
||||
@@ -2851,6 +2852,11 @@
|
||||
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
|
||||
"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": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/path-type/-/path-type-4.0.0.tgz",
|
||||
@@ -6087,6 +6093,11 @@
|
||||
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
|
||||
"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": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/path-type/-/path-type-4.0.0.tgz",
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
"marked": "^4.2.12",
|
||||
"mavon-editor": "^3.0.0",
|
||||
"nprogress": "^0.2.0",
|
||||
"path-to-regexp": "^6.2.1",
|
||||
"pinia": "^2.0.32",
|
||||
"pinia-plugin-persistedstate": "^3.2.0",
|
||||
"vue": "^3.2.47",
|
||||
|
||||
84
Yi.Bbs.Vue3/src/components/Breadcrumb/index.vue
Normal file
84
Yi.Bbs.Vue3/src/components/Breadcrumb/index.vue
Normal 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>
|
||||
@@ -14,15 +14,16 @@ import directive from "./directive"; // directive
|
||||
|
||||
import "./permission";
|
||||
|
||||
const app = createApp(App);
|
||||
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
|
||||
app.component(key, component);
|
||||
}
|
||||
|
||||
const pinia = createPinia();
|
||||
pinia.use(piniaPluginPersistedstate);
|
||||
|
||||
app.use(pinia);
|
||||
directive(app);
|
||||
app.use(router);
|
||||
app.mount("#app");
|
||||
(async () => {
|
||||
const app = createApp(App);
|
||||
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
|
||||
app.component(key, component);
|
||||
}
|
||||
const pinia = createPinia();
|
||||
pinia.use(piniaPluginPersistedstate);
|
||||
app.use(pinia);
|
||||
directive(app);
|
||||
app.use(router);
|
||||
await router.isReady();
|
||||
app.mount("#app");
|
||||
})();
|
||||
|
||||
@@ -42,6 +42,9 @@ const router = createRouter({
|
||||
name: "index",
|
||||
path: "/index",
|
||||
component: () => import("../views/home/Index.vue"),
|
||||
meta: {
|
||||
title: "首页",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "article",
|
||||
@@ -52,6 +55,9 @@ const router = createRouter({
|
||||
name: "discuss",
|
||||
path: "/discuss/:plateId?",
|
||||
component: () => import("../views/Discuss.vue"),
|
||||
meta: {
|
||||
title: "板块",
|
||||
},
|
||||
},
|
||||
{
|
||||
//artType:discuss主题、article文章
|
||||
@@ -65,6 +71,14 @@ const router = createRouter({
|
||||
path: "/profile",
|
||||
component: () => import("../views/profile/Index.vue"),
|
||||
},
|
||||
{
|
||||
name: "themeCover",
|
||||
path: "/article/:discussId",
|
||||
component: () => import("../views/Article.vue"),
|
||||
meta: {
|
||||
title: "主题封面",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{ path: "/:pathMatch(.*)*", name: "NotFound", component: NotFound },
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<el-button
|
||||
style="width: 100%; margin-bottom: 0.8rem"
|
||||
@click="loadDiscuss(true)"
|
||||
>首页</el-button
|
||||
>主题封面</el-button
|
||||
>
|
||||
<el-button
|
||||
v-hasPer="['bbs:article:add']"
|
||||
@@ -51,6 +51,7 @@
|
||||
<el-col :span="14">
|
||||
<el-row class="left-div">
|
||||
<el-col :span="24">
|
||||
<Breadcrumb :breadcrumbsList="breadcrumbsList" class="breadcrumb" />
|
||||
<!-- {{ discuss.user }} -->
|
||||
<AvatarInfo
|
||||
:size="50"
|
||||
@@ -170,7 +171,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { h, ref, onMounted } from "vue";
|
||||
import { h, ref, onMounted, watch } from "vue";
|
||||
import AvatarInfo from "@/components/AvatarInfo.vue";
|
||||
import InfoCard from "@/components/InfoCard.vue";
|
||||
import ArticleContentInfo from "@/components/ArticleContentInfo.vue";
|
||||
@@ -185,6 +186,8 @@ import {
|
||||
del as articleDel,
|
||||
get as articleGet,
|
||||
} from "@/apis/articleApi.js";
|
||||
import Breadcrumb from "@/components/Breadcrumb/index.vue";
|
||||
|
||||
//数据定义
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
@@ -205,6 +208,11 @@ const currentNodeKey = route.params.articleId;
|
||||
//目录数据
|
||||
const catalogueData = ref([]);
|
||||
|
||||
// 面包屑导航列表
|
||||
const breadcrumbsList = ref([]);
|
||||
// 当前文章名称
|
||||
const currentArticle = ref("");
|
||||
|
||||
//子文章初始化
|
||||
const loadArticleData = async () => {
|
||||
const response = await articleall(route.params.discussId);
|
||||
@@ -315,6 +323,7 @@ const updateArticle = (node, data) => {
|
||||
};
|
||||
//单机节点
|
||||
const handleNodeClick = async (data) => {
|
||||
currentArticle.value = data?.name;
|
||||
//跳转路由
|
||||
|
||||
router.push(`/article/${route.params.discussId}/${data.id}`);
|
||||
@@ -343,6 +352,35 @@ onMounted(async () => {
|
||||
await loadDiscuss();
|
||||
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>
|
||||
<style scoped>
|
||||
.comment {
|
||||
@@ -425,4 +463,8 @@ h2 {
|
||||
.tab-divider {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.breadcrumb {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1642,6 +1642,11 @@
|
||||
"resolved" "https://registry.npmmirror.com/path-parse/-/path-parse-1.0.7.tgz"
|
||||
"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":
|
||||
"integrity" "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw=="
|
||||
"resolved" "https://registry.npmmirror.com/path-type/-/path-type-4.0.0.tgz"
|
||||
|
||||
Reference in New Issue
Block a user