面包屑导航
静态面包屑
动态面包屑
静态面包屑
指的是:在每个页面中写死对应的面包屑菜单,缺点也很明显
- 每个页面都得写一遍
- 页面路径结构变化了,得手动更改
简单来说就是 不好维护,不好扩展
。
动态面包屑
- 根据当前的
url
自动生成面包屑导航菜单
无论之后路径发生了什么变化 动态面包屑
都会正确的进行计算
那么在后续的实现过程中,我们将会分成三大步骤来实现
创建,渲染基本的面包屑组件
计算面包屑结构数据
根据数据渲染动态面包屑内容
创建,渲染基本的面包屑组件
- 创建 components/BreadCrumb.vue
vue
<template>
<el-breadcrumb class="breadcrumb" separator="/">
<el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
<el-breadcrumb-item><a href="/">活动管理</a></el-breadcrumb-item>
<el-breadcrumb-item>活动列表</el-breadcrumb-item>
<!-- 面包屑的最后一项 -->
<el-breadcrumb-item>
<span class="no-redirect">活动详情</span>
</el-breadcrumb-item>
</el-breadcrumb>
</template>
<script setup></script>
<style lang="scss" scoped>
.breadcrumb {
display: inline-block;
font-size: 14px;
line-height: 50px;
margin-left: 8px;
::v-deep .no-redirect {
color: #97a8be;
cursor: text;
}
}
</style>
- 挂载到 NavBar 上面
vue
<template>
<div class="navbarContent">
<div class="sidebaropen">
<SideBarOpen></SideBarOpen>
</div>
<div class="breadcrumb">
<BreadCrumb></BreadCrumb>
</div>
<div class="avatar">
<Avater></Avater>
</div>
</div>
</template>
<script setup></script>
<style lang="scss" scoped>
.navbarContent {
width: 100%;
height: 60px;
border-bottom: 1px solid #ccc;
.sidebaropen {
float: left;
margin-top: 15px;
margin-left: 20px;
cursor: pointer;
}
.breadcrumb {
float: left;
margin-left: 10px;
margin-top: 1px;
}
.avatar {
width: 80px;
height: 50px;
float: right;
margin-right: 20px;
margin-top: 5px;
}
}
</style>
动态计算面包屑结构数据
现在我们是完成了一个静态的 面包屑,接下来咱们就需要依托这个静态的菜单来完成动态的。
对于现在的静态面包屑来说,他分成了两个组件:
el-breadcrumb
:包裹性质的容器el-breadcrumb-item
:每个单独项
如果我们想要完成动态的,那么就需要 **依据动态数据,渲染 el-breadcrumb-item
所以说接下来我们需要做的事情就很简单了
- 动态数据
- 渲染
el-breadcrumb-item
- 点击事件
- 动画效果
最后合计
我们希望可以创建一个数组,每个数组中每个item
都表示一个路由信息
我们还得渲染面包屑,里面写好点击事件 最后如下
- components/BreadCrumb.vue
vue
<template>
<el-breadcrumb class="breadcrumb" separator="/">
<transition-group name="breadcrumb">
<el-breadcrumb-item
v-for="(item, index) in breadcrumbData"
:key="item.path"
>
<!-- 不可点击项 -->
<span v-if="index === breadcrumbData.length - 1" class="no-redirect">{{
generateTitle(item.meta.title)
}}</span>
<!-- 可点击项 -->
<a v-else class="redirect" @click.prevent="onLinkClick(item)">{{
generateTitle(item.meta.title)
}}</a>
</el-breadcrumb-item>
</transition-group>
</el-breadcrumb>
</template>
<script setup>
import { generateTitle } from "@/utils/i18n";
import { useVariables } from "@/stores/variables";
const route = useRoute();
console.log(route);
// 生成数组数据
const breadcrumbData = ref([]);
const getBreadcrumbData = () => {
breadcrumbData.value = route.matched.filter(
(item) => item.meta && item.meta.title
);
};
// 监听路由变化时触发
watch(
route,
() => {
getBreadcrumbData();
},
{
immediate: true,
}
);
// 处理点击事件
const router = useRouter();
const onLinkClick = (item) => {
console.log(item);
router.push(item.path);
};
// 主题更换
console.log(useVariables().variables.menuBg);
const linkHoverColor = ref(useVariables().variables.menuBg);
</script>
<style lang="scss" scoped>
.breadcrumb {
display: inline-block;
font-size: 14px;
line-height: 50px;
margin-left: 8px;
.redirect {
color: #666;
font-weight: 600;
}
.redirect:hover {
// 将来需要进行主题替换,所以这里不去写死样式
color: v-bind(linkHoverColor);
}
:deep(.no-redirect) {
color: #97a8be;
cursor: text;
}
}
</style>
动画效果的 css
新建 styles/transition
样式文件
scss
.breadcrumb-enter-active,
.breadcrumb-leave-active {
transition: all 0.5s;
}
.breadcrumb-enter-from,
.breadcrumb-leave-active {
opacity: 0;
transform: translateX(20px);
}
.breadcrumb-leave-active {
position: absolute;
}
在 styles/index
中导入
scss
@import "./transition.scss";