使用requestAnimationFrame实现轮播图下面的进度轮播点

需求如下:给普通轮播图下面增加速度轮播点
在这里插入图片描述
代码场景使用elm的弹窗弹的轮播图,然后配合elm的走马灯,核心代码就是openAnimation一个方法而已,仅供大家参考,若有更简洁点的方法欢迎评论区共同探讨

<template>
  <div class="dialog">
    <el-dialog
      :append-to-body="true"
      :close-on-click-modal="false"
      :modal-append-to-body="true"
      :visible.sync="dialogVisible"
      :show-close="false"
      width="560px"
    >
      <div class="content">
        <div class="close" @click="close">
          <img src="../images/icon_close.png" alt="" />
        </div>
        <el-carousel
          indicator-position="none"
          arrow="never"
          @change="changeActive"
          height="406px"
          :interval="interval"
          ref="carousel"
        >
          <el-carousel-item
            v-for="item in imageList"
            :key="item.id"
            @click.native="goSign"
          >
            <img class="myimg" :src="item.webCoverImgUrl" alt="" />
            <!-- webCoverImgUrl -->
          </el-carousel-item>
        </el-carousel>
        <!-- 自定义指示器 -->
        <div class="list" v-if="imageList.length > 1">
          <div
            class="indicator"
            v-for="(item, index) in imageList"
            :key="item.id"
            @mouseenter="toChangeActive(index)"
          >
            <div
              class="active"
              ref="active"
              :style="{ transform: `translateX(${-(targetWidth - width)}px)` }"
              v-show="index === currentIdx"
            ></div>
          </div>
        </div>
      </div>
    </el-dialog>
  </div>
</template>

<script>
export default {
  data () {
    return {
      companyName: '',
      type: 0,
      params: {},
      activityList: [],
      currentIdx: 0,
      // raf控制的width
      width: 0,
      // 目标width,要跟轮播点width保持一致
      targetWidth: 136,
      interval: 3000
    }
  },
  props: {
    dialogVisible: {
      type: Boolean,
      default: true
    },
    imageList: {
      type: Array,
      defaule: () => {
        return []
      }
    }
  },
  mounted () {},
  watch: {
    imageList: {
      immediate: true,
      handler (newValue, oldValue) {
        if (newValue.length > 1) {
          this.changeActive(0)
        }
      }
    }
  },
  methods: {
    toChangeActive (idx) {
      this.$refs.carousel.setActiveItem(idx)
    },
    changeActive (val) {
      if(this.imageList.length<=1) return
      this.currentIdx = val
      this.openAnimation()
    },
    openAnimation () {
      // console.log('准备开启动画');
      window.cancelAnimationFrame(this.handle)
      this.initailTimer = 0
      this.preTimer = 0
      this.useTimer = 0
      this.width = 0
      const fn = timer => {
        !this.initailTimer && (this.initailTimer = timer)
        //  判断当时所用的时间与初始时间之差
        // 重复调用这个,他会在下一次显示器刷新时执行回调,
        this.useTimer = timer - this.initailTimer
        // 两次运行间隔浪费了多少时间,就决定下一次渲染要加多少,保持匀速
        this.preTimer &&
          (this.width +=
            (this.targetWidth / this.interval) * (timer - this.preTimer))
        this.preTimer = timer
        // console.log(this.width, timer)
        if (this.useTimer >= this.interval) {
          console.log('动画时间到达')
          // window.cancelAnimationFrame(this.handle)
        } else {
          // 继续做动画
          window.requestAnimationFrame(fn)
        }
      }
      this.handle = window.requestAnimationFrame(fn)
    },
    close () {
      this.$emit('changeDialogVisible', false)
    },
    goSign () {
      this.$emit('openDialog')
      this.$emit('changeDialogVisible', false)
    }
  },
  destroyed () {
    window.cancelAnimationFrame(this.handle)
  },
  components: {}
}
</script>

<style lang="scss" scoped>
/deep/ .el-dialog {
  border-radius: 8px;
  background-color: transparent;
}
/deep/ .el-dialog__body {
  padding: 0;
}
/deep/ .el-dialog__header {
  display: none;
}

.content {
  height: 380px;
  width: 100%;
  cursor: pointer;
  position: relative;
  .close {
    width: 20px;
    height: 20px;
    // background: #155882;
    // border: 1px dashed rgba(16, 139, 177, 0.4);
    // border-radius: 31px;
    // position: absolute;
    // top: -8px;
    // right: -7px;
    // text-align: center;
    // color: #108bb1;
    // line-height: 16px;
    // cursor: pointer;
    // z-index: 999;
    position: absolute;
    top: -8px;
    right: -7px;
    z-index: 999;
    cursor: pointer;
    > img {
      width: 100%;
      height: 100%;
    }
  }
  /deep/ .el-carousel__item {
    display: flex;
    // align-items: center;
    justify-content: center;
  }
  img {
    // width: 100%;
    max-width: 560px;
    max-height: 370px;
    // height: 100%;
  }
  // /deep/ .el-carousel__indicators {
  //   //  transform: translate(-50%,100px);
  // }
}
.list {
  position: absolute;
  bottom: -16px;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 999;
  .indicator {
    // width: 68px;
    // height: 6px;
    width: 136px;
    height: 12px;
    margin: 0 -18px;
    background: rgba(255, 255, 255, 0.2);
    border-radius: 6px;
    overflow: hidden;
    // 为了动画更流畅
    transform: scale(0.5);
    .active {
      width: 136px;
      transform: translateX(-100%);
      height: 100%;
      background-color: #fff;
    }
  }
  // margin-top: 380px;
}
// .block {
//     width: 0;
//     height: 0;
//     border-top: 30px solid skyblue;
//     border-right: 30px solid transparent;
//     border-left: 30px solid transparent;
// }
</style>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值