8000
We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
本篇文章主要讲解如何来封装一个面包屑组件,充当基本的导航角色
本文也是《通俗易懂的中后台系统建设指南》系列的第七篇文章,该系列旨在告诉你如何来构建一个优秀的中后台管理系统
在本文中,你可以了解到面包屑概念、应用场景等知识点,学到面包屑的的封装思路及实践应用
文章最后也会给到本文中示例的全部源码
面包屑导航(Breadcrumb Navigation)这个概念来自童话故事“汉赛尔和格莱特”,当汉赛尔和格莱特穿过森林时,不小心迷路了,但是他们发现沿途走过的地方都撒下了面包屑,让这些面包屑来帮助他们找到回家的路
面包屑导航被当作一种有效的视觉救援,指引用户在网站层级中所处的位置,你需要了解以下三种信息
面包屑组件在 B 端产品是比较常见的元素,它扮演着重要的导航角色,主要应用场景包括:
在 Ant Design 的面包屑设计板块中,有这么一段话:Breadcrumb 的本质是了解当前所处页面的位置,并能向上导航
在本文中,我们会按照以下思路进行逐步分析实现:
ElBreadcrumb
本文默认使用 Element Plus 的 ElBreadcrumb 作为二次封装的基础组件,你可以先了解一下 ElBreadcrumb 组件及 Api
本文开发环境是: Vue3 + TS + Tailwindcss + scss
首先,先要来了解一个属性,Vue Router 中的 router.matched,它是一个数组,表示当前路由对象中与当前路径匹配的所有路由记录(RouteRecord),简单一点来说,router.matched 用于存储匹配的路由记录
router.matched
RouteRecord
<script setup lang="ts"> import { useRoute } from 'vue-router'; const currentRoute = useRoute(); console.log(currentRoute); </script>
利用 matched,可以动态生成页面的面包屑,展示从父级到子级的层级关系
matched
我们新建一个 breadcrumb.vue 文件,表示这个文件用于二次封装 ElBreadcrumb,然后写入以下内容:
breadcrumb.vue
<script setup lang="ts"> import { ElBreadcrumb, ElBreadcrumbItem } from 'element-plus'; import { useRoute } from 'vue-router'; import type { RouteLocationMatched } from 'vue-router'; import { computed } from 'vue'; defineOptions({ name: 'Breadcrumb', }); const currentRoute = useRoute(); /** 获取路由路径 */ const getPath = (item: RouteLocationMatched): string | Object => { if (!item) return ''; if (item.meta?.isReadonlyBreadcrumb) return ''; return { path: item.redirect ? item.redirect : item.path }; }; /** 面包屑列表 */ const breadcrumbList = computed(() => currentRoute.matched.filter((item) => !item.meta.isHideBreadcrumb), ); </script> <template> <ElBreadcrumb> <ElBreadcrumbItem v-for="item in breadcrumbList" :key="item.path" :to="getPath(item)"> <span>{{ item.meta.title }}</span> </ElBreadcrumbItem> </ElBreadcrumb> </template>
上面内容中实现了一个基本的面包屑:
breadcrumbList
getPath
满足原有配置属性比较简单,利用 $attrs 即可实现,具有的参数配置,参阅 Breadcrumb 面包屑
$attrs
<ElBreadcrumb v-bind="$attrs"> //... </ElBreadcrumb>
面包屑除了基本的导航文本展示外,可以有更多丰富的内容,比如每个路由的元信息中可能会存储一个 icon 图标文本,再比如点击路由时的跳转方式,下面我们会来丰富这些配置:
创建一个 typing.ts 文件,表示类型文件,定义一个类型 BreadcrumbProps:
typing.ts
BreadcrumbProps
export interface BreadcrumbProps { /** * 如果设置该属性为 true, 导航将不会留下历史记录 * @default false * @see https://element-plus.org/zh-CN/component/breadcrumb.html#breadcrumbitem-attributes */ replace?: boolean; /** * 是否显示面包屑图标 * @default true */ isShowIcon?: boolean; }
基本实现:
<script setup lang="ts"> import { ElBreadcrumb, ElBreadcrumbItem } from 'element-plus'; import { useRoute } from 'vue-router'; import type { RouteLocationMatched } from 'vue-router'; import type { BreadcrumbProps } from './typing'; import { computed, h } from 'vue'; import { AppIcon } from '@/components/common/app-icon'; defineOptions({ name: 'Breadcrumb', }); const currentRoute = useRoute(); const props = withDefaults(defineProps<BreadcrumbProps>(), { replace: false, isHideIcon: false, }); //... /** 渲染图标 */ const renderIcon = (item: RouteLocationMatched) => { if (!props.isShowIcon || !item.meta.icon) return null; return h(AppIcon, { icon: item.meta.icon }); }; </script> <template> <ElBreadcrumb v-bind="$attrs" :class="breadcrumbClassName"> <ElBreadcrumbItem v-for="item in breadcrumbList" :key="item.path" :to="getPath(item)" :replace > <div class="space-x-1"> <Component :is="renderIcon(item)" /> <span>{{ item.meta.title }}</span> </div> </ElBreadcrumbItem> </ElBreadcrumb> </template>
注意,请确保你的路由 meta 信息中拥有一个 icon 属性,否则图标相关的内容将不起效
icon
上面代码中,实现了图标的显隐配置、ElBreadcrumbItem 的 replace 属性配置等
ElBreadcrumbItem
replace
需要注意的是文中的 AppIcon 组件是内部实现的组件,你可以在这里找到它。当然,你也可以替换成 ElIcon
AppIcon
ElIcon
Element Plus 中面包屑组件的样式变化不多,算是文本形式,顶多配置一下图标分隔符,我们下面来对基本的面包屑进行样式美化
还记得我们上面定义了一个 BreadcrumbProps 嘛,在这基础上,我们新添一个 styleType,它接受一个联合类型:
styleType
type BreadcrumbStyleType = 'default' | 'arrow' | 'parallelogram'; export type BreadcrumbStyleObj = { [key in BreadcrumbStyleType]: string; }; export interface BreadcrumbProps { //... /** * 面包屑样式 * @default default */ type?: BreadcrumbStyleType; }
<script setup lang="ts"> import type { BreadcrumbEmits, BreadcrumbProps, BreadcrumbStyleObj } from './typing'; //... const props = withDefaults(defineProps<BreadcrumbProps>(), { replace: false, isHideIcon: false, styleType: 'default',// 默认为文本样式 }); /** 获取面包屑Class样式 */ const breadcrumbClassName = computed(() => { const className: BreadcrumbStyleObj = { arrow: 'breadcrumb-arrow', default: 'breadcrumb-default', parallelogram: 'breadcrumb-parallelogram', }; return className[props.styleType]; }); </script> <template> <ElBreadcrumb v-bind="$attrs" :class="breadcrumbClassName"> <ElBreadcrumbItem v-for="item in breadcrumbList" :key="item.path" :to="getPath(item)" :replace > <div class="space-x-1"> <Component :is="renderIcon(item)" /> <span>{{ item.meta.title }}</span> </div> </ElBreadcrumbItem> </ElBreadcrumb> </template>
在上面这一步,我们主要做的事,是给 ElBreadcrumb 加上不同的类名来应用样式
既然类名加上了,我们需要给到各类名对应的样式,复制如下样式即可
注意,这里默认你使用了 Scss
<style scoped lang="scss"> $height: 24px; @mixin breadcrumb__inner($padding: 0 4px 0 16px, $bgColor: var(--el-fill-color-light)) { position: relative; z-index: 1; display: inline-flex; align-items: center; height: $height; padding: $padding; text-decoration: none; background-color: $bgColor; } .breadcrumb { //箭头样式 &-arrow { :deep(.el-breadcrumb__item) { position: relative; margin-right: 12px; .el-breadcrumb__inner { @include breadcrumb__inner(); &::before, &::after { position: absolute; top: 0; z-index: -1; content: ''; border: calc($height/2) solid transparent; } &::before { left: -1px; border-left-color: var(--el-bg-color); } &::after { right: -23px; border-left-color: var(--el-fill-color-light); } &:hover { background: var(--el-fill-color); &::after { border-left-color: var(--el-fill-color); } } } } :deep(.el-breadcrumb__separator) { display: none; } } //平行四边形样式 &-parallelogram { :deep(.el-breadcrumb__item) { position: relative; margin-right: 8px; .el-breadcrumb__inner { @include breadcrumb__inner(4px 10px, transparent); &::before { position: absolute; top: 0; left: 0; z-index: -1; width: 100%; height: 100%; content: ''; background-color: var(--el-fill-color-light); transform: skew(-20deg); } } } :deep(.el-breadcrumb__separator) { display: none; } } } </style>
然后,根据属性 styleType 传入不同的值,即可得到默认文本、箭头、平行四边形的面包屑样式
默认面包屑:
箭头面包屑:
平行四边形面包屑:
面包屑根据你的路由、地址会进行不断变化,我们给它一个平滑的动画效果来更符合视觉感受
这里需要用到 Vue 的内置组件 <TransitionGroup> ,你可以在 Vue 官网的 TransitionGroup 章节找到更多信息
<TransitionGroup>
写入以下动画
/* 面包屑切换动画 */ .breadcrumb-basic-enter-active { transition: all 0.25s; } .breadcrumb-basic-enter-from, .breadcrumb-basic-leave-active { opacity: 0; transform: translateX(20px) skewX(-20deg); }
然后在封装的组件中使用 <TransitionGroup> 包裹
<template> <ElBreadcrumb v-bind="$attrs" :class="breadcrumbClassName"> <TransitionGroup name="breadcrumb-basic"> //... </TransitionGroup> </ElBreadcrumb> </template>
这个动画的最终效果是这样的:
本文中的所有实例源码,你可以在这里找到
系列专栏地址:GitHub 博客 | 掘金专栏 | 思否专栏
实战项目:vue-clean-admin
专栏往期回顾:
文章如有错误或需要改进之处,欢迎指正
The text was updated successfully, but these errors were encountered:
No branches or pull requests
前言
本篇文章主要讲解如何来封装一个面包屑组件,充当基本的导航角色
在本文中,你可以了解到面包屑概念、应用场景等知识点,学到面包屑的的封装思路及实践应用
什么是面包屑
面包屑导航(Breadcrumb Navigation)这个概念来自童话故事“汉赛尔和格莱特”,当汉赛尔和格莱特穿过森林时,不小心迷路了,但是他们发现沿途走过的地方都撒下了面包屑,让这些面包屑来帮助他们找到回家的路
面包屑的作用如何定义?
面包屑导航被当作一种有效的视觉救援,指引用户在网站层级中所处的位置,你需要了解以下三种信息
面包屑的应用场景
面包屑组件在 B 端产品是比较常见的元素,它扮演着重要的导航角色,主要应用场景包括:
在 Ant Design 的面包屑设计板块中,有这么一段话:Breadcrumb 的本质是了解当前所处页面的位置,并能向上导航
面包屑的封装思路及目标
在本文中,我们会按照以下思路进行逐步分析实现:
ElBreadcrumb
的原有配置属性ElBreadcrumb
的样式美化本文默认使用 Element Plus 的
ElBreadcrumb
作为二次封装的基础组件,你可以先了解一下 ElBreadcrumb 组件及 Api面包屑的基本导航功能
首先,先要来了解一个属性,Vue Router 中的
router.matched
,它是一个数组,表示当前路由对象中与当前路径匹配的所有路由记录(RouteRecord
),简单一点来说,router.matched
用于存储匹配的路由记录利用
matched
,可以动态生成页面的面包屑,展示从父级到子级的层级关系我们新建一个
breadcrumb.vue
文件,表示这个文件用于二次封装ElBreadcrumb
,然后写入以下内容:上面内容中实现了一个基本的面包屑:
breadcrumbList
:面包屑列表,主要是通过router.matched
Api 实现getPath
:获取路由路径的函数满足原有配置属性
满足原有配置属性比较简单,利用
$attrs
即可实现,具有的参数配置,参阅 Breadcrumb 面包屑面包屑个性化(图标隐现、路由跳转方式)
面包屑除了基本的导航文本展示外,可以有更多丰富的内容,比如每个路由的元信息中可能会存储一个 icon 图标文本,再比如点击路由时的跳转方式,下面我们会来丰富这些配置:
创建一个
typing.ts
文件,表示类型文件,定义一个类型BreadcrumbProps
:基本实现:
注意,请确保你的路由 meta 信息中拥有一个
icon
属性,否则图标相关的内容将不起效上面代码中,实现了图标的显隐配置、
ElBreadcrumbItem
的replace
属性配置等面包屑的样式美化及切换动画
样式美化
Element Plus 中面包屑组件的样式变化不多,算是文本形式,顶多配置一下图标分隔符,我们下面来对基本的面包屑进行样式美化
还记得我们上面定义了一个
BreadcrumbProps
嘛,在这基础上,我们新添一个styleType
,它接受一个联合类型:在上面这一步,我们主要做的事,是给
ElBreadcrumb
加上不同的类名来应用样式既然类名加上了,我们需要给到各类名对应的样式,复制如下样式即可
然后,根据属性
styleType
传入不同的值,即可得到默认文本、箭头、平行四边形的面包屑样式默认面包屑:
箭头面包屑:
平行四边形面包屑:
切换动画
面包屑根据你的路由、地址会进行不断变化,我们给它一个平滑的动画效果来更符合视觉感受
这里需要用到 Vue 的内置组件
<TransitionGroup>
,你可以在 Vue 官网的 TransitionGroup 章节找到更多信息写入以下动画
然后在封装的组件中使用
<TransitionGroup>
包裹这个动画的最终效果是这样的:
参考资料
源码
本文中的所有实例源码,你可以在这里找到
了解更多
系列专栏地址:GitHub 博客 | 掘金专栏 | 思否专栏
实战项目:vue-clean-admin
专栏往期回顾:
交流讨论
文章如有错误或需要改进之处,欢迎指正
The text was updated successfully, but these errors were encountered:
5E85