分享一个简单优雅的轮播图组件

先看效果

使用方法:

<script  lang="ts" setup>
import CarouselVue from '@/components/Carousel.vue';

const data = [
  {
    href: "",
    imgLink: 'https://cdn.cnbj1.fds.api.mi-img.com/mi-mall/454c1da2c5b64a3f2c07c5a4c01aa9c4.jpg?thumb=1&w=2452&h=920&f=webp&q=90'
  },
  {
    href: '',
    imgLink: 'https://cdn.cnbj1.fds.api.mi-img.com/mi-mall/6d90fda69e63bf93ae62120901bafc0e.jpg?thumb=1&w=2452&h=920&f=webp&q=90'
  },
  {
    href: '',
    imgLink: 'https://cdn.cnbj1.fds.api.mi-img.com/mi-mall/dce8b00fb3b4ebecbcf72353bff8a030.jpg?thumb=1&w=2452&h=920&f=webp&q=90'
  },
  {
    href: '',
    imgLink: 'https://cdn.cnbj1.fds.api.mi-img.com/mi-mall/b836faf5402e8c14b626507b5c2e0ed5.jpeg?w=2452&h=920'
  }
];
</script>

<template>
  <div class="box">
    <CarouselVue :data="data" width="900" height="340">
    </CarouselVue>
  </div>
</template>

<style lang="scss" scoped>
.box {
  margin-top: 100px;
  margin-left: 30px;
}
</style>

实现源码

<script  lang="ts" setup>
import { onMounted, ref } from 'vue';

// types
export interface Carousel {
  href: string,
  imgLink: string
}

export interface Props {
  width: string | number,
  height: string | number,
  data: Carousel[],
  delay?: number
}

//vars
const props = withDefaults(defineProps<Props>(), {
  delay: 3000
});

// states
const current = ref(0);
const timer = ref<number | null>(null);


// methods
function goto(indx: number) {
  current.value = indx
}

function goRight() {
  current.value = (current.value + 1) % props.data.length;
}

function goLeft() {
  current.value = (current.value - 1 + props.data.length) % props.data.length;
}

function active(idx: number) {
  return idx === current.value
}

function start() {
  clearTimeout(timer.value as number);
  timer.value = window.setInterval(() => {
    goRight();
  }, props.delay);
}

function stop() {
  window.clearInterval(timer.value as number);
  timer.value = null;
}

onMounted(async () => {
  start();
})
</script>

<template>
  <div class="carousel" :style="{ width: width + 'px', height: height + 'px' }">
    <div class="img-list">
      <div class="img-wrapper" v-for="(item, idx) in data" :class="{ active: active(idx) }" @mouseenter="stop"
        @mouseleave="start">
        <a :href="item.href">
          <img :src="item.imgLink" alt="图片">
        </a>
      </div>
    </div>

    <div class="arrow">
      <div class="left" @click="goLeft"><i class="iconfont icon-arrow-left"></i></div>
      <div class="right" @click="goRight"><i class="iconfont icon-arrow-right"></i></div>
    </div>

    <ul class="circle-list">
      <li class="circle" v-for="idx in data.length" @click="goto(idx - 1)" :class="{ active: idx - 1 === current }">
      </li>
    </ul>
  </div>
</template>


<style lang="scss" scoped>
.carousel {
  position: relative;

  .img-list {
    position: relative;
    height: 100%;

    .img-wrapper {
      position: absolute;
      top: 0;
      left: 0;
      opacity: 0;
      transition: 0.6s ease-in-out;

      &.active {
        opacity: 1;
      }

      img {
        width: 100%;
      }
    }
  }

  .arrow div {
    position: absolute;
    top: 50%;
    transform: translate(0, -50%);
    width: 25px;
    height: 35px;
    line-height: 35px;
    background-color: rgba(0, 0, 0, 0.4);
    color: white;

    text-align: center;
    user-select: none;
    cursor: pointer;

    .iconfont {
      font-size: 20px;
    }
  }

  .arrow div.left {
    left: 0;
    border-top-right-radius: 18px;
    border-bottom-right-radius: 18px;
  }

  .arrow div.right {
    right: 0;
    border-top-left-radius: 18px;
    border-bottom-left-radius: 18px;
  }

  .circle-list {
    display: flex;
    position: absolute;
    bottom: 10px;
    right: 10px;
    z-index: 8;

    .circle {
      margin: 0 5px;
      width: 6px;
      height: 6px;
      border: 2px solid #fff;
      background-color: rgba(0, 0, 0, 0.4);
      border-radius: 50%;
      cursor: pointer;

      &.active {
        background-color: rgba(255, 255, 255, 0.4);
      }
    }
  }
}
</style>
vuejs·javascript
262 views
Comments
登录后评论
Sign In
·

学习一下