likes
comments
collection
share

自己封装一个组件

作者站长头像
站长
· 阅读数 64

闲来无事,脑子里突然出现了一个想法,组件库里的组件是怎么封装的?为什么拿过来就能直接使用?我能不能自己写一个呢?于是乎就在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
评论
请登录