Vue实现面包屑导航的正确方式
前言
面包屑导航(BreadcrumbNavigation)这个概念来自童话故事“汉赛尔和格莱特”,当汉赛尔和格莱特穿过森林时,不小心迷路了,但是他们发现沿途走过的地方都撒下了面包屑,让这些面包屑来帮助他们找到回家的路。所以,面包屑导航的作用是告诉访问者他们在网站中的位置以及如何返回。
正如童话故事里的面包屑的作用,网站中的面包屑组件是为了告诉我们在网站中的位置。
然而,在看了一些 admin 项目后,发现面包屑的使用并不符合逻辑。
以 82k+ star 的 vue-element-admin 为例:
我们发现点击某篇文章的编辑后,导航路径从 首页/综合实例/文章列表 变为 首页/综合实例/编辑文章,而用户正确的路径是 首页/综合实例/文章列表/编辑文章。
分析 vue-element-admin 这种行为的原因
这里贴上其官网自动生成面包屑的代码:
function getBreadcrumb() { // only show routes with meta.title let matched = this.$route.matched.filter(item => item.meta && item.meta.title) const first = matched[0] if (!this.isDashboard(first)) { matched = [{ path: '/dashboard', meta: { title: 'Dashboard' }}].concat(matched) } this.levelList = matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false) }
我们可以发现作者用到了 $route.matched
,它的作用是:一个路由匹配到的所有路由记录会暴露为 $route
对象(还有在导航守卫中的路由对象)的 $route.matched
数组。
那么我看来看看其路由是如何注册的:
可以看到列表和编辑被注册到了同一级,matched
最后自然不会包含列表这一级。而且我们可以看到完全使用 matched 的缺点:
图中有一级综合实例,这个路径是因为在路由注册时,它与列表或者编辑页面形成了上下级关系。
所以,如果你的系统可以接收这个效果,可以参考 vue-element-admin 的行为。
怎么生成正确的路径
至于怎么生成正确的路径,如:首页/综合实例/文章列表/编辑文章。
我的方案是:每个页面都写自己的面包屑路径!
这是最灵活,适应性最强的一种方式了,当然缺点也非常明显,如果你的页面很多,那改动的成本将会非常高。
所以,我又研究了第二种方式,它依旧是依赖于路由数据生成的。
当然前面我们已经知道了 router 注册的数组,只能表示组件在页面结构上的一些父子关系,并不能正确表示用户访问的路径。
所以我们需要额外维护一份,表示页面访问关系的树形结构(可以是环形,但是代码需要额外处理,且不一定能表示正确的用户访问路径,我们此次不讨论)。
import { createRouter, createWebHistory } from 'vue-router' import HomeView from '../views/HomeView.vue' import ListView from '@/views/ListView.vue' import EditView from '@/views/EditView.vue' import {useBreadcrumbStore} from "@/store/useBreadcrumbStore"; import DetailView from "@/views/DetailView.vue"; import _ from "lodash"; import ForthView from "@/views/ForthView.vue"; const router = createRouter({ history: createWebHistory(import.meta.env.BASE_URL), routes: [ { path: '/', name: 'home', meta: { title: '首页' }, component: HomeView }, { path: '/list', name: 'list', meta: { title: '列表' }, component: ListView }, { path: '/detail', name: 'detail', meta: { title: '详情', }, component: DetailView }, { path: '/forth', name: 'forth', meta: { title: '第四级页面', }, component: ForthView, }, { path: '/edit', name: 'edit', meta: { title: '编辑' }, component: EditView }, { path: '/about', name: 'about', meta: { title: '关于' }, component: () => import('../views/AboutView.vue') } ] }) const breadcrumbsStruct = [ { name: 'home', children: [ { name: 'list', children: [ { name: 'edit' }, { name: 'detail', children: [ { name: 'forth', }, ], } ] } ] }, { name: 'about' } ] router.afterEach((to) => { const target = to.name; const data: string[] = [] let finalData = data; function dfs(arr: any[]) { // 在 breadcrumbsStruct 查找 target,且记录下树上的路径 if (!arr || !arr.length) { return; } for (let i=0; i<arr.length; i++) { const item = arr[i]; data.push(item.name); if (item.name === target) { finalData = _.cloneDeep(data); break; } // 向深一级查找,查不到应该回溯 dfs(item.children); data.pop(); } } dfs(breadcrumbsStruct); const routeList = router.getRoutes(); const routeInfoList = finalData.map(item => { const info = routeList.find(r => r.name === item); if (info) { return info; } else { console.error('构建路径失败'); } }); const store = useBreadcrumbStore(); store.setBreadcrumbs(routeInfoList); }) export default router
出了 router
的注册外,额外维护一份 breadcrumbsStruct
数据,其中 name
用于 router
中注册的页面匹配,为了方便匹配,规定它是不能重复的。children
表示从这个页面可以打开哪些页面。
在 afterEach
路由钩子中,我们利用回溯算法生成面包屑数据。
完整的工程代码在此处。
效果演示
页面做的比较简陋,但是我需要的效果达到了。
总结
最后的方案,需要额外维护一份数据,这是需要成本的,但是这个成本可控。
面包屑导航属于项目中的小细节,一般不会引起重视,但是仔细想想,诸如 vue-element-admin 的实现确实生成的不是真正的用户访问路径。
到此这篇关于Vue实现面包屑导航的正确方式的文章就介绍到这了,更多相关Vue面包屑内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
如何使用Vue3+elementPlus的Tree组件实现一个拖拽文件夹管理
最近在做一个文件夹管理的功能,要实现一个树状的拖拽文件夹面板,里面包含两种元素,文件夹以及文件,这篇文章主要介绍了使用Vue3+elementPlus的Tree组件实现一个拖拽文件夹管理 ,需要的朋友可以参考下2023-09-09
最新评论