【通用组件】封装一个通用轮播组件

2023/06/29 12:16:49

当前页面组件位置:示例组件open in new window通用轮播组件open in new window

项目中如果存在多种轮播组件,可以将轮播逻辑封装到一个单独的组件中。

示例

示例组件源码

<template>
  <div
    class="carousel-wrapper"
    :style="{ height: `${itemHeight * maxDisplayNum}px` }"
  >
    <Carousel
      v-model:list.sync="list"
      :maxDisplayNum="maxDisplayNum"
      :delay="delay"
      :transition="transition"
    >
      <div class="item" v-for="item in list" :key="item">
        {{ item }}
      </div>
    </Carousel>
  </div>
</template>

<script>
import Carousel from "./Carousel.vue";
export default {
  components: {
    Carousel,
  },
  data() {
    return {
      list: ["item 1", "item 2", "item 3"],
      maxDisplayNum: 2,
      itemHeight: 40,
      delay: 3000,
      duration: 0.5,
    };
  },
  computed: {
    transition() {
      return `${this.duration}s`;
    },
  },
};
</script>

<style scoped>
.carousel-wrapper {
  width: 500px;
  border: 1px solid #000;
  overflow: hidden;
  margin-right: 20px;
}

.item {
  height: 40px;
  line-height: 40px;
  border: 1px solid #eee;
  box-sizing: border-box;
}
</style>

通用轮播组件源码

<template>
  <div
    class="carousel"
    :style="{
      transform: wrapperStyleTransform,
      transition: wrapperStyleTransition,
    }"
  >
    <slot />
  </div>
</template>

<script>
let timer = null;

// 公共轮播组件容器
export default {
  props: {
    // 滚动间隔/ms
    delay: {
      default: 3000,
    },
    // 滚动效果配置
    transition: {
      default: "1s",
    },
    // 列表数据
    list: {
      default: [],
    },
    // 一屏可以展示的条目数量
    maxDisplayNum: {
      default: 1,
    },
  },
  data() {
    return {
      isReset: false,
      displayIndex: 0,
    };
  },
  computed: {
    wrapperStyleTransform() {
      return `translateY(-${(100 / this.maxDisplayNum) * this.displayIndex}%)`;
    },
    wrapperStyleTransition() {
      if (this.isReset) {
        return "0s";
      }
      return this.transition;
    },
  },
  methods: {
    startMove() {
      this.isReset = false;
      timer = setTimeout(() => {
        this.displayIndex++;
        if (this.displayIndex === this.list.length - this.maxDisplayNum) {
          setTimeout(() => {
            this.isReset = true;
            this.displayIndex = 0;
          }, this.delay / 2);
        }
        this.startMove();
      }, this.delay);
    },
  },
  mounted() {
    if (this.list.length > this.maxDisplayNum) {
      const list = this.list.concat(this.list.slice(0, this.maxDisplayNum));
      this.$emit("update:list", list);
      this.startMove();
    }
  },
  beforeDestroy() {
    clearTimeout(timer);
  },
};
</script>

<style scoped>
.carousel {
  width: 100%;
  height: 100%;
}
</style>