一.为什么需要面包屑
面包屑导航(BreadcrumbNavigation)这个概念来自童话故事“汉赛尔和格莱特”,当汉赛尔和格莱特穿过森林时,不小心迷路了,但是他们发现在沿途走过的地方都撒下了面包屑,让这些面包屑来帮助他们找到回家的路。
看完上面的介绍,相信各位已经理解了面包屑组件的使用场景了。对的,没错,是用来记录我们点击了哪些页面,方便我们再返回之前某一个页面。
当网页进行了多次跳转后,用户可能早就已经晕头转向了。作为程序猿的我们可能通过地址栏参数还可以分清楚当前处于哪一个位置,终归网页是要展示给用户。用户来使用的话,没有面包屑导航的话,可能就对网页产生了抵触心理,使用面包屑导航将每次跳转的页面记录下来,可以很好解决这一问题。
二.初级封装
1.实现思路
- 在public目录下的index.html中引入cdn的字体图标资源
<link rel="stylesheet" href="//at.alicdn.com/t/font_2143783_iq6z4ey5vu.css">
- 将需要外部传入的值定义为自定义属性
- 将外部写在标签内部的内容放置在默认插槽中
- 代码演示
在src/libs目录下新建bread-crumbs-item.vue文件,
代码示例:
<template>
<div class="bread-crumbs-item">
<RouterLink v-if="to" :to="to"><slot /></RouterLink>
<span v-else><slot /></span>
<i class="iconfont icon-angle-right"></i>
</div>
</template>
<script>
export default {
name: 'BreadCurmbsItem',
props: {
to: {
type: [String, Object]
}
}
}
</script>
在src/libs目录下新建bread-crumbs.vue文件,,将导航的每一项放置在默认插槽中
<template>
<div class='bread-crumbs'>
<slot />
</div>
</template>
<script>
export default {
name: 'BreadCrumbs'
}
</script>
<style scoped lang='less'>
.bread-crumbs {
display: flex;
padding: 25px 10px;
&-item {
a {
text-decoration: none;
color: #666;
transition: all 0.4s;
&:hover {
color: #27ba9b;
}
}
}
i {
font-style: normal;
font-size: 12px;
margin-left: 5px;
margin-right: 5px;
line-height: 22px;
}
}
</style>
- 使用
使用的时候,有多少个二级导航就使用几个BreadCrumbsItem
代码如下(示例):
<template>
<div class="home-banner">
<!-- 面包屑 -->
<BreadCrumbs>
<BreadCrumbsItem to="/">首页</BreadCrumbsItem>
<BreadCrumbsItem to="/xxx">小龙虾</BreadCrumbsItem>
<BreadCrumbsItem >米线</BreadCrumbsItem>
</BreadCrumbs>
</div>
</template>
<script>
export default {
name: 'App',
setup() {
}
}
</script>
- 不足
在最后一个导航后面会有多余的一个>指示标识
三.高阶封装
修改BreadCurmbsItem
组件内的代码:
template>
<div class="bread-crumbs-item">
<RouterLink v-if="to" :to="to"><slot /></RouterLink>
<span v-else><slot /></span>
</div>
</template>
<script>
export default {
name: 'BreadCurmbsItem',
props: {
to: {
type: [String, Object]
}
}
}
</script>
修改BreadCrumbs.vue
中的代码:
<script>
import { h } from 'vue'
export default {
name: 'BreadCrumbs',
render () {
// 用法
// 1. template 标签去除,单文件组件
// 2. 返回值就是组件内容
// 3. vue2.0 的h函数传参进来的,vue3.0 的h函数导入进来
// 4. h 第一个参数 标签名字 第二个参数 标签属性对象 第三个参数 子节点
// 需求
// 1. 创建bread-crumbs父容器
// 2. 获取默认插槽内容
// 3. 去除bread-crumbs-item组件的i标签,因该由render函数来组织
// 4. 遍历插槽中的item,得到一个动态创建的节点,最后一个item不加i标签
// 5. 把动态创建的节点渲染再bread-crumbs标签中
const items = this.$slots.default()
const dymanicItems = []
items.forEach((item, i) => {
dymanicItems.push(item)
if (i < (items.length - 1)) {
dymanicItems.push(h('i', { class: 'iconfont icon-angle-right' }))
}
})
return h('div', { class: 'bread-crumbs' }, dymanicItems)
}
}
</script>
<style lang='less'>
// 将scope属性去除,目的是为了样式穿透至item组件中
.bread-crumbs {
display: flex;
padding: 25px 10px;
&-item {
a {
text-decoration: none;
color: #666;
transition: all .4s;
&:hover {
color: #27ba9b;
}
}
}
i {
font-size: 12px;
margin-left: 5px;
margin-right: 5px;
line-height: 22px;
// 样式的方式,不合理
// &:last-child {
// display: none;
// }
}
}
</style>
- 使用
<template>
<!-- 面包屑 -->
<BreadItem>
<BreadCrumbsItem to="/doc/switch">switch开关</BreadCrumbsItem>
<BreadCrumbsItem to="/doc/button">button按钮</BreadCrumbsItem>
<BreadCrumbsItem to="/doc/dialog">dialog对话框</BreadCrumbsItem>
<BreadCrumbsItem to="/doc/tabs">tabs标签页</BreadCrumbsItem>
<BreadCrumbsItem to="/doc/carousel">carousel轮播图</BreadCrumbsItem>
<BreadCrumbsItem to="/doc/city">city城市组件</BreadCrumbsItem>
<BreadCrumbsItem to="/doc/pagination">pagination分页器</BreadCrumbsItem>
<BreadCrumbsItem to="/doc/inputnumber">inputnumber计时器</BreadCrumbsItem>
<BreadCrumbsItem to="/doc/checkBox">checkBox复选框</BreadCrumbsItem>
<BreadCrumbsItem to="/doc/breadItem">breadItem面包屑</BreadCrumbsItem>
</BreadItem>
</template>
<script lang="ts">
import BreadItem from "../libs/BreadItem.vue";
import BreadCrumbsItem from "../libs/BreadCrumbsItem.vue";
export default {
components: { BreadItem, BreadCrumbsItem },
};
</script>
-
效果图展示
面包屑效果图
四.使用jsx优化
可以将高阶写法中的功能代码使用jsx的方式进行重写,jsx写出来的代码更加的简洁明了。
name: 'BreadCrumbs',
render () {
// vue2的render函数的形参是 h 函数
// vue3中h函数是导入的
// createElement(标签名称, 标签的属性, 标签的子元素)
// console.dir(this.$slots.default())
// 获取XtxBread组件的所有的插槽里面填充组件实例
const items = this.$slots.default()
const results = []
items.forEach((item, index) => {
results.push(item)
// 手动生成一个i图标,添加到面包屑项目的后面
if (index < items.length - 1) {
results.push(<i className='iconfont icon-angle-right'></i>)
}
})
return <div className='bread-crumbs'>{results}</div>
}
}
网友评论