Vue 封装轮播图组件

vp-carousel.vue

<template>
  <div class="vp-carousel" :style="{ height: height + 'px' }">
    <div class="vp-carousel-arrow">
      <ul class="vp-carousel-arrow-ul">
        <li
          class="vp-carousel-arrow-li"
          v-for="(slot, index) in $slots.default"
          :key="index"
        >
          <button
            :class="{
              'vp-carousel-arrow-button': true,
              'vp-carousel-button-isActive':
                currentIndex === index ? true : false,
            }"
          ></button>
        </li>
      </ul>
    </div>
    <div class="vp-carousel-arrow-aside" v-if="isShowAsideBtn">
      <button class="vp-carousel-arrow-aside-left" @click="leftBtn"><</button>
      <button class="vp-carousel-arrow-aside-right" @click="rightBtn">></button>
    </div>
    <div class="vp-carousel-container">
      <slot></slot>
    </div>
  </div>
</template>

<script>
export default {
  name: "VpCarousel",
  provide() {
    return {
      VpCarousel: this,
    };
  },
  props: {
    height: {
      type: String,
      default: "300",
    },
    interval: {
      type: Number,
      default: 3000,
    },
    hasTransition: {
      type: Boolean,
      default: true,
    },
    transitionTime: {
      type: Number,
      default: 0.5,
    },
  },
  data() {
    return {
      timer: null,
      timeoutTimer: null,
      currentIndex: 0,
      isShowAsideBtn: false,
    };
  },
  created() {},
  mounted() {
    let width = this.$el.clientWidth;
    let slots = this.$slots.default;
    let slotsLength = slots.length;
    let __this = this;
    this.$el.addEventListener("mouseover", function () {
      __this.isShowAsideBtn = true;
    });
    this.$el.addEventListener("mouseleave", function () {
      __this.isShowAsideBtn = false;
    });

    // 图片默认位置
    for (let i = 0, l = slotsLength; i < l; i++) {
      slots[i].elm.style.transform = `translate(${i * 100}%)`;
    }

    // 设置过渡
    this.$nextTick(() => {
      if (this.hasTransition) {
        this.timeoutTimer = setTimeout(() => {
          for (let i = 0, l = slotsLength; i < l; i++) {
            slots[i].elm.style.transition = `transform ${this.transitionTime}s`;
          }
        });
      }
    });

    // 移动内容
    this.timer = setInterval(() => {
      this.intervalChangeFunc(slots, slotsLength);
    }, this.interval);

    let btns = this.$el.getElementsByClassName("vp-carousel-arrow-button");
    let _this = this;
    btns.forEach((btn, index) => {
      btn.addEventListener("mouseover", function () {
        _this.currentIndex = index;
        clearInterval(_this.timer);
        _this.changefirst(index);
        for (let i = 0, l = btns.length; i < l; i++) {
          btns[i].classList.remove("vp-carousel-button-isActive");
        }
        this.classList.add("vp-carousel-button-isActive");
      });
      btn.addEventListener("mouseleave", function () {
        _this.timer = setInterval(() => {
          _this.intervalChangeFunc(slots, slotsLength);
        }, _this.interval);
      });
    });
  },
  beforeDestroy() {
    clearInterval(this.timer);
    clearTimeout(this.timeoutTimer);
  },
  methods: {
    changefirst(index) {
      let slots = this.$slots.default;
      let slotsLength = slots.length;
      let oldCurrentIndex;
      for (let i = 0, l = slotsLength; i < l; i++) {
        let transform = slots[i].elm.style.transform;
        let reg = /(-)?[0-9]+/g;
        let transformNum = Number(transform.match(reg)[0]);
        if (transformNum === 0) {
          oldCurrentIndex = i;
          break;
        }
      }
      for (let i = 0; i < slotsLength; i++) {
        if (i === index) {
          slots[i].elm.style.transform = "translate(0%)";
        } else if (i < index) {
          let trans = slots[i].elm.style.transform;
          let reg1 = /(-)?[0-9]+/g;
          let transNum = Number(trans.match(reg1)[0]);
          slots[i].elm.style.transform = `translate(-${(index - i) * 100}%)`;
        } else if (i > index) {
          let trans = slots[i].elm.style.transform;
          let reg1 = /(-)?[0-9]+/g;
          let transNum = Number(trans.match(reg1)[0]);
          slots[i].elm.style.transform = `translate(${(i - index) * 100}%)`;
        }
      }
    },
    intervalChangeFunc(slots, slotsLength) {
      for (let i = 0, l = slotsLength; i < l; i++) {
        let transform = slots[i].elm.style.transform;
        let reg = /(-)?[0-9]+/g;
        let transformNum = Number(transform.match(reg)[0]);
        if (transformNum === 0) {
          this.currentIndex = i + 1;
          if (this.currentIndex === slotsLength) {
            this.currentIndex = 0;
          }
        }
        slots[i].elm.style.transform = `translate(${transformNum - 100}%)`;
      }

      for (let i = 0, l = slotsLength; i < l; i++) {
        let transform = slots[i].elm.style.transform;
        let reg = /(-)?[0-9]+/g;
        let transformNum = Number(transform.match(reg)[0]);
        let lastSlot = slots[slotsLength - 1].elm.style.transform;
        let regExp = /[0-9]+/g;
        let transformLastSlotNum = Number(lastSlot.match(regExp)[0]);
        if (transformNum <= -200) {
          let transformArr = [];
          for (let i = 0, l = slotsLength; i < l; i++) {
            let transform = slots[i].elm.style.transform;
            let reg = /(-)?[0-9]+/g;
            transformArr.push(Number(transform.match(reg)[0]));
          }
          // 降序
          let newTransformArr = transformArr.sort(function (a, b) {
            return b - a;
          });
          slots[i].elm.style.transform = `translate(${
            newTransformArr[0] + 100
          }%)`;
        }
      }
    },
    leftBtn() {
      let slots = this.$slots.default;
      let slotsLength = slots.length;
      this.currentIndex -= 1;
      if (this.currentIndex < 0) {
        this.currentIndex = slotsLength - 1;
        clearInterval(this.timer);
        this.changefirst(this.currentIndex);
        this.timer = setInterval(() => {
          this.intervalChangeFunc(slots, slotsLength);
        }, this.interval);
      } else {
        clearInterval(this.timer);
        this.changefirst(this.currentIndex);
        this.timer = setInterval(() => {
          this.intervalChangeFunc(slots, slotsLength);
        }, this.interval);
      }
    },
    rightBtn() {
      let slots = this.$slots.default;
      let slotsLength = slots.length;
      this.currentIndex += 1;
      if (this.currentIndex > slotsLength - 1) {
        this.currentIndex = 0;
        clearInterval(this.timer);
        this.changefirst(this.currentIndex);
        this.timer = setInterval(() => {
          this.intervalChangeFunc(slots, slotsLength);
        }, this.interval);
      } else {
        clearInterval(this.timer);
        this.changefirst(this.currentIndex);
        this.timer = setInterval(() => {
          this.intervalChangeFunc(slots, slotsLength);
        }, this.interval);
      }
    },
  },
};
</script>
<style scoped>
.vp-carousel {
  width: 100%;
  position: relative;
  overflow: hidden;
}
.vp-carousel-container {
  position: relative;
  width: 100%;
  height: 100%;
}
.vp-carousel-arrow {
  position: absolute;
  display: flex;
  height: auto;
  z-index: 2;
  bottom: 0;
  left: 50%;
  transform: translateX(-50%);
}
.vp-carousel-arrow-ul {
  list-style: none;
  display: flex;
  padding: 0;
  margin: 0;
  justify-content: center;
  align-content: flex-end;
}
.vp-carousel-arrow-li {
  display: flex;
  align-items: center;
  padding: 10px 0;
}

.vp-carousel-arrow-button,
.vp-carousel-arrow-aside-left,
.vp-carousel-arrow-aside-right {
  margin: 0;
  padding: 0;
  outline: none;
  border-radius: 0;
  background-color: transparent;
  line-height: inherit;
  width: max-content;
}
.vp-carousel-arrow-button::after,
.vp-carousel-arrow-aside-left::after,
.vp-carousel-arrow-aside-right::after {
  border: none;
}
.vp-carousel-arrow-button {
  background-color: lightblue;
  border: none;
  width: 30px;
  height: 2px;
  border-radius: 2px;
  margin: 3px 5px;
  padding: 2px;
}
.vp-carousel-button-isActive {
  background-color: aqua;
}
.vp-carousel-arrow-aside-left,
.vp-carousel-arrow-aside-right {
  background-color: rgba(0, 0, 0, 0.6);
  width: 50px;
  height: 100px;
  border: none;
}
.vp-carousel-arrow-aside {
  position: absolute;
  width: 100%;
  display: flex;
  justify-content: space-between;
  top: 50%;
  transform: translateY(-50%);
  z-index: 3;
}
.vp-carousel-arrow-aside-left,
.vp-carousel-arrow-aside-right {
  font-size: 50px;
  color: #ffffff;
}
</style>

vp-carousel-item.vue


<template>
  <div class="vp-carousel-item" :style="{ height: VpCarousel.height + 'px' }">
    <slot></slot>
  </div>
</template>

<script>
export default {
  name: "VpCarouselItem",
  inject: ["VpCarousel"],
  data() {
    return {};
  },
  created() {},
  mounted() {
    let slots = this.VpCarousel.$slots.default;
  },
};
</script>
<style scoped>
.vp-carousel-item {
  position: absolute;
  display: inline-block;
  width: 100%;
  height: 100%;
  top: 0;
  left: 0;
  z-index: 1;
}
</style>

Carousel Attributes

属性名类型属性值描述默认值
heightString“600”走马灯高度“300”
intervalNumber切换延迟毫秒3000
hasTransitionBooleantrue | false是否执行过渡动画true
transitionTimeNumber过渡动画毫秒0.5

如需要其他更多组件,请移步到本人开发的 Vue 组件库文档:Vpro_UI
如果觉得好的话,请在 Github 上点个 star ,非常感谢!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,以下是一个基于Vue.js实现的轮播图组件: ```html <template> <div class="slider"> <div class="slider-wrapper" :style="{ transform: 'translateX(-' + currentImage * 100 + '%)' }"> <div class="slider-item" v-for="(image, index) in images" :key="index" :style="{ backgroundImage: 'url(' + image + ')' }"> </div> </div> <div class="slider-dots"> <span class="dot" v-for="(image, index) in images" :key="index" :class="{ active: currentImage === index }" @click="goToImage(index)"> </span> </div> </div> </template> <script> export default { data() { return { currentImage: 0, interval: null, }; }, props: { images: { type: Array, required: true, }, intervalTime: { type: Number, default: 3000, }, }, methods: { startSlider() { this.interval = setInterval(() => { this.currentImage++; if (this.currentImage >= this.images.length) { this.currentImage = 0; } }, this.intervalTime); }, goToImage(index) { this.currentImage = index; clearInterval(this.interval); this.startSlider(); }, }, mounted() { this.startSlider(); }, beforeUnmount() { clearInterval(this.interval); }, }; </script> <style scoped> .slider { position: relative; overflow: hidden; } .slider-wrapper { display: flex; transition: transform 0.5s ease-out; } .slider-item { width: 100%; height: 0; padding-bottom: 56.25%; background-position: center; background-size: cover; } .slider-dots { position: absolute; bottom: 10px; left: 50%; transform: translateX(-50%); display: flex; } .slider-dots .dot { width: 10px; height: 10px; border-radius: 50%; background-color: #ccc; margin-right: 10px; cursor: pointer; } .slider-dots .active { background-color: #333; } </style> ``` 这个轮播图组件接受一个`images`数组作为参数,每个元素是一个图片的URL。可以通过设置`intervalTime`属性来控制自动播放的时间间隔,默认为3秒。组件内部使用了`setInterval`函数来实现自动播放,并且在组件销毁前使用`clearInterval`函数清除定时器。底部的小圆点会根据当前显示的图片来更新样式,并且可以点击切换到对应的图片。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值