自己封装一个组件
闲来无事,脑子里突然出现了一个想法,组件库里的组件是怎么封装的?为什么拿过来就能直接使用?我能不能自己写一个呢?于是乎就在vue文档里搜了一下

看起来也不难,写一个面包屑试试。先去饿了么上面看一眼

饿了么是把面包屑组件和导航组件结合使用,将每一个导航封装为一个组件。主要参数:separator-分隔符 to-路由跳转对象。了解个差不多了,先新建两个组件

把架子搭好
// index.vue
<template>
<div class="test-bread">
<slot />
</div>
</template>
// BreadItem.vue
<template>
<div class="xtx-bread-item">
<span><slot /></span>
<i>{{ 分隔符 }}</i>
</div>
</template>
那么问题来了,分隔符数据是位于组件中,而对于分隔符数据的使用是在导航的组件中使用,如何解决呢?忽然想到用 provide / inject 不就可以了吗
// index.vue
<script lang="ts" setup name="TestBread">
import { provide } from 'vue'
const props = defineProps({
separator: {
type: String,
default: ''
}
})
provide('separator', props.separator)
</script>
// BreadItem.vue
<script lang="ts" setup name="TestBreadItem">
import { inject } from 'vue'
defineProps({
to: {
type: String
}
})
const separator = inject('separator')
</script>
还有就是如果有to,这个导航就是可以点击跳转的,怎么实现呢?通过 defineProps 接收 to。 如果to存在 => 渲染一个router-link标签;如果to没有 => 渲染一个span标签
// BreadItem.vue
<template>
<div class="test-bread-item">
<router-link v-if="to" :to="to"><slot /></router-link>
<span v-else><slot /></span>
<i>{{ 分隔符 }}</i>
</div>
</template>
这个问题解决了,然后对比了一下饿了么,发现我的分隔符没有写默认值,因为是通过 inject 接收的,所以直接用v-if。我默认是用了一个右箭头的图标
/ BreadItem.vue
<template>
<div class="test-bread-item">
<router-link v-if="to" :to="to"><slot /></router-link>
<span v-else><slot /></span>
<i v-if="separator">{{ separator }}</i>
<i v-else class="iconfont icon-angle-right"></i>
</div>
</template>
默认值是有了,可是分隔符是加在每个导航后面的,最后会多出来一个,要把最后一个分隔符隐藏

现在差不多就完成了,再把样式完善一下就可以了。 面包屑组件:
// index.vue
<script lang="ts" setup name="TestBread">
import { provide } from 'vue'
const props = defineProps({
separator: {
type: String,
default: ''
}
})
provide('separator', props.separator)
</script>
<template>
<div class="test-bread">
<slot />
</div>
</template>
<style scoped lang="scss">
.test-bread {
display: flex;
padding: 25px 10px;
&-item {
a {
color: #666;
transition: all 0.4s;
&:hover {
color: red;
}
}
}
i {
font-size: 12px;
margin-left: 5px;
margin-right: 5px;
line-height: 22px;
}
}
</style>
导航组件
// BreadItem.vue
<script lang="ts" setup name="TestBreadItem">
import { inject } from 'vue'
defineProps({
to: {
type: String
}
})
const separator = inject('separator')
</script>
<template>
<div class="test-bread-item">
<router-link v-if="to" :to="to"><slot /></router-link>
<span v-else><slot /></span>
<i v-if="separator">{{ separator }}</i>
<i v-else class="iconfont icon-angle-right"></i>
</div>
</template>
<style lang="scss" scoped>
.test-bread-item {
i {
margin: 0 6px;
font-size: 10px;
}
// 最后一个i隐藏
&:nth-last-of-type(1) {
i {
display: none;
}
}
}
</style>
最后注册到全局就可以使用了,跟饿了么用起来一毛一样!
转载自:https://juejin.cn/post/7159629616561258533