对于一名前端程序员来说封装组件是一个必备技能。当我们在日常的工作中总有所用的组件库满足不了需求的情况,这就需要我们有封装组件的基本功了。
封装组件,可以提高我们代码的复用性,提高工作效率,提高代码的可阅读性。

组件我自己的理解的话,分为两种吧,一种是工具类的组件,一种是页面级别的组件,工具类的组件就是说封装后,在以后的项目中如果用相同的应用场景时,可复用。页面类组件的话就是将一个大的页面分成很多的小组件,然后进行拼接,组成大页面,让页面看起来不臃肿,美观,提高代码的阅读性。方便后期的维护管理。

1.轮播图组件的封装

在父组件中留出位置放子组件(子组件为全局组件。)。在pinia中发送请求拿数据 在拿到数据后cope value 去拿泛型。父传子的方式去在子组件中接收数据,在子组件中去做相应的业务逻辑,自动播放,按钮,前进后退等功能。

在pinia中发请求拿到数据


import request  from '@/utils/request'
import { defineStore } from 'pinia'
import {IApiRes, banneritem } from '@/types/data'
export default defineStore('home',{
  state:()=>{
    return{
      bannerlist: [] as banneritem[]
    }
  },
  actions:{
    // 获取轮播图数据
    async getBannerList(){
      const res = await request.get<IApiRes<banneritem[]>>('/home/banner')
      console.log(res,'2222222');
      this.bannerlist = res.data.result
    },

types/data中进行泛型补充:

// 所有的接口的通用类型
export interface IApiRes<T> {
  code: string
  msg: string
  result: T
}
// banner轮播图类型
export  type banneritem={
  id: string;
  imgUrl: string;
  hrefUrl: string;
  type: string;
}

父组件中:

<script lang="ts" setup>
import useStore from '@/store';
//子组件引入
import Carousel from '@/components/Carousel/index.vue';
const { home}  = useStore()
home.getBannerList()
</script>
<template>
  <div class="home-banner">
    <!-- 轮播图 -->
       <!-- <carousel :slides="home.Bannerlist" :autoPlay="true" :duration="2000"></carousel> -->
    <Carousel :slides="home.bannerlist" :autoplay="true" :duration="2000"  ></Carousel>
  </div>
</template>

在父组件中使用传入相应的参数即可。

在子组件中:相应的样式及业务逻辑,都有注释,我就不一一写了。

<script lang="ts" setup name="Carousel">
import { banneritem } from '@/types/data';
import { onBeforeMount, onMounted, ref } from 'vue';
// 接收父组件传过来的数据
const {slides, autoplay=true, duration=3000} =  defineProps<{
  slides:banneritem[],
  autoplay:boolean,
  duration:number
}>()
// 当前选择的是那一张图片。
let active = ref(0)
// 左侧箭头
const hleft = ()=>{
active.value--
if(active.value < 0){
active.value = slides.length-1
}
}
// 右侧箭头
const hright = ()=>{
active.value++
if(active.value > slides.length - 1){
active.value = 0
}
}
let timer = -1
// 鼠标离开开启自动播放
const start = ()=>{
  if(autoplay){
    // 在ts中,使用定时器,注意:window.setInterval
    timer =window.setInterval(()=>{
    hright()  
    },duration)
  }
}
// 鼠标进入停止自动播放
const stop = ()=>{
clearInterval(timer)
}
// 点击小圆点跳转
const ind= (id:number)=>{
  active.value = id
}
//在页面加载时 自动播放
onMounted(()=>{
  start()
})
// 在页面关闭时,销毁组件 停止播放
onBeforeMount(()=>{
  stop()
})
</script>
<template>
 <!-- fade类表示当前图片可见 -->
  <div class="xtx-carousel" @mouseleave="start" @mouseenter="stop" >
    <ul class="carousel-body">
      <li class="carousel-item " 
      :class="{fade :index === active}"
      v-for="(item,index ) in slides" :key="item.id">
        <RouterLink to="/">
          <img
            :src="https://juejin.im/post/7123925565505011749/item.imgUrl"
            alt=""
          />
        </RouterLink>
      </li>
    </ul>
    <!-- 左边箭头 -->
    <a href="javascript:;" class="carousel-btn prev" @click="hleft"
      ><i class="iconfont icon-angle-left"></i
    ></a>
    <!-- 右边箭头 -->
    <a href="javascript:;" class="carousel-btn next" @click="hright"
      ><i class="iconfont icon-angle-right"></i
    ></a>
    <!-- 小圆点 -->
    <div class="carousel-indicator">
      <span v-for="(item,index) in slides" :key="item.id" :class="{active:active === index}" @mouseenter="ind(index)" ></span>
    </div>
  </div>
</template>
<style scoped lang="less">
.xtx-carousel {
  width: 100%;
  height: 100%;
  min-width: 300px;
  min-height: 150px;
  position: relative;
  .carousel {
    &-body {
      width: 100%;
      height: 100%;
    }
    &-item {
      width: 100%;
      height: 100%;
      position: absolute;
      left: 0;
      top: 0;
      opacity: 0;
      transition: opacity 0.5s linear;
      &.fade {
        opacity: 1;
        z-index: 1;
      }
      img {
        width: 100%;
        height: 100%;
      }
    }
    &-indicator {
      position: absolute;
      left: 0;
      bottom: 20px;
      z-index: 2;
      width: 100%;
      text-align: center;
      span {
        display: inline-block;
        width: 12px;
        height: 12px;
        background: rgba(0, 0, 0, 0.2);
        border-radius: 50%;
        cursor: pointer;
        ~ span {
          margin-left: 12px;
        }
        &.active {
          background: #fff;
        }
      }
    }
    &-btn {
      width: 44px;
      height: 44px;
      background: rgba(0, 0, 0, 0.2);
      color: #fff;
      border-radius: 50%;
      position: absolute;
      top: 228px;
      z-index: 2;
      text-align: center;
      line-height: 44px;
      opacity: 0;
      transition: all 0.5s;
      &.prev {
        left: 20px;
      }
      &.next {
        right: 20px;
      }
    }
  }
  &:hover {
    .carousel-btn {
      opacity: 1;
    }
  }
}
</style>