文章目录
- 01-顶级类目-面包屑组件-初级
- 02-顶级类目-面包屑组件-高级
01-顶级类目-面包屑组件-初级
目的: 封装一个简易的面包屑组件,适用于两级场景。
大致步骤:
- 准备静态的
xtx-bread.vue
组件 - 定义
props
暴露parentPath
parentName
属性,默认插槽,动态渲染组件 - 在
library/index.js
注册组件,使用验证效果。
落的代码:
- 基础结构 src/components/library/xtx-bread.vue
<template>
<div class='xtx-bread'>
<div class="xtx-bread-item">
<RouterLink to="/">首页</RouterLink>
</div>
<i class="iconfont icon-angle-right"></i>
<div class="xtx-bread-item">
<RouterLink to="/category/10000">电器</RouterLink>
</div>
<i class="iconfont icon-angle-right"></i>
<div class="xtx-bread-item">
<span>空调</span>
</div>
</div>
</template>
<script>
export default {
name: 'XtxBread'
}
</script>
<style scoped lang='less'>
.xtx-bread{
display: flex;
padding: 25px 10px;
&-item {
a {
color: #666;
transition: all .4s;
&:hover {
color: @xtxColor;
}
}
}
i {
font-size: 12px;
margin-left: 5px;
margin-right: 5px;
line-height: 22px;
}
}
</style>
- 定义props进行渲染
src/components/library/xtx-bread.vue
<template>
<div class='xtx-bread'>
<div class="xtx-bread-item">
<RouterLink to="/">首页</RouterLink>
</div>
<i class="iconfont icon-angle-right"></i>
+ <div class="xtx-bread-item" v-if="parentName">
+ <RouterLink v-if="parentPath" :to="parentPath">{{parentName}}</RouterLink>
+ <span v-else>{{parentName}}</span>
+ </div>
+ <i v-if="parentName" class="iconfont icon-angle-right"></i>
<div class="xtx-bread-item">
+ <span><slot /></span>
</div>
</div>
</template>
<script>
export default {
name: 'XtxBread',
+ props: {
+ parentName: {
+ type: String,
+ default: ''
+ },
+ parentPath: {
+ type: String,
+ default: ''
+ }
+ }
}
</script>
- 注册使用
src/components/library/index.js
+import 'XtxBread' from './xtx-bread.vue'
export default {
install (app) {
+ app.component(XtxBread.name, XtxBread)
使用: <XtxBread parentPath="/category/1005000" parentName="电器">空调</XtxBread>
总结: 采用基本的封装手法,灵活度不是很高。
02-顶级类目-面包屑组件-高级
目的: 封装一个高复用的面包屑组件,适用于多级场景。认识 render 选项和 h 函数。
参考element-ui的面包屑组件:
大致步骤:
- 使用插槽和封装选项组件完成面包屑组件基本功能,但是最后一项多一个图标。
- 学习 render 选项,h 函数 的基本使用。
- 通过 render 渲染,h 函数封装面包屑功能。
落的代码:
- 我们需要两个组件,
xtx-bread
和xtx-bread-item
才能完成动态展示。
定义单项面包屑组件src/components/library/xtx-bread-item.vue
<template>
<div class="xtx-bread-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: 'XtxBreadItem',
props: {
to: {
type: [String, Object]
}
}
}
</script>
- 在
library/index.js
注册
+import 'XtxBreadItem' from './xtx-bread-item.vue'
export default {
install (app) {
+ app.component(XtxBreadItem.name, XtxBread)
- 过渡版,你发现结构缺少风格图标,如果在item中加上话都会有图标,但是最后一个是不需要的。
<template>
<div class='xtx-bread'>
<slot />
</div>
</template>
<script>
export default {
name: 'XtxBread'
}
</script>
<!-- 去掉scoped全局作用 -->
<style lang='less'>
<!-- 面包屑 -->
<XtxBread>
<XtxBreadItem to="/">首页</XtxBreadItem>
<XtxBreadItem to="/category/1005000">电器</XtxBreadItem>
<XtxBreadItem >空调</XtxBreadItem>
</XtxBread>
-
终极版,使用render函数自己进行拼接创建。
createElement
render
render选项与h函数 -
指定组件显示的内容:
new Vue({选项})
- el 选项,通过一个选择器找到容器,容器内容就是组件内容
- template 选项,
<div>组件内容</div>
作为组件内容 - render选项,它是一个函数,函数回默认传人createElement的函数(h),这个函数用来创建结构,再render函数返回渲染为组件内容。它的优先级更高。
//import App from './App.vue'
//new Vue({
// render:h=>h(App)
//}).mount('#app')
// h() =====> createElement()
// h(App) =====> 根据APP组件创建html结构
// render的返回值就是html结构,渲染到#app容器
// h() 函数参数,1.节点名称 2. 属性|数据 是对象 3. 子节点
xtx-bread-item.vue
<template>
<div class="xtx-bread-item">
<RouterLink v-if="to" :to="to"><slot /></RouterLink>
<span v-else><slot /></span>
- <i class="iconfont icon-angle-right"></i>
</div>
</template>
xtx-bread.vue
<script>
import { h } from 'vue'
export default {
name: 'XtxBread',
render () {
// 用法
// 1. template 标签去除,单文件组件
// 2. 返回值就是组件内容
// 3. vue2.0 的h函数传参进来的,vue3.0 的h函数导入进来
// 4. h 第一个参数 标签名字 第二个参数 标签属性对象 第三个参数 子节点
// 需求
// 1. 创建xtx-bread父容器
// 2. 获取默认插槽内容
// 3. 去除xtx-bread-item组件的i标签,因该由render函数来组织
// 4. 遍历插槽中的item,得到一个动态创建的节点,最后一个item不加i标签
// 5. 把动态创建的节点渲染再xtx-bread标签中
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: 'xtx-bread' }, dymanicItems)
}
}
</script>
<style lang='less'>
// 去除 scoped 属性,目的:然样式作用到xtx-bread-item组件
.xtx-bread{
display: flex;
padding: 25px 10px;
// ul li:last-child {}
// 先找到父元素,找到所有的子元素,找到最后一个,判断是不是LI,是就是选中,不是就是无效选择器
// ul li:last-of-type {}
// 先找到父元素,找到所有的类型为li的元素,选中最后一个
&-item {
a {
color: #666;
transition: all .4s;
&:hover {
color: @xtxColor;
}
}
}
i {
font-size: 12px;
margin-left: 5px;
margin-right: 5px;
line-height: 22px;
// 样式的方式,不合理
// &:last-child {
// display: none;
// }
}
}
</style>
- 使用代码
<!-- 面包屑 -->
<XtxBread>
<XtxBreadItem to="/">首页</XtxBreadItem>
<XtxBreadItem to="/category/1005000">电器</XtxBreadItem>
<XtxBreadItem >空调</XtxBreadItem>
</XtxBread>
- 总结,一下知识点
- render 是vue提供的一个渲染函数,优先级大于el,template等选项,用来提供组件结构。
- 注意:
- vue2.0 render函数提供h(createElement)函数用来创建节点
- vue3.0 h(createElement)函数有 vue 直接提供,需要按需导入
- this.$slots.default() 获取默认插槽的node结构,按照要求拼接结构。
- h函数的传参 tag 标签名|组件名称, props 标签属性|组件属性, node 子节点|多个节点
- 具体参考 render
- 注意:不要在 xtx-bread 组件插槽写注释,也会被解析。