vue项目中实现无缝轮播并动态更新数据

<template>
    <div class="chart-out-wrapper">
      <div class="chart-wrapper"
           ref="swiper"
           @mouseover="mouseHover"
           @mouseout="mouseOut"
      >
        <barChart v-for="(item, index) in categoryDataList"
                  :key="index"
                  class="chart-size"
                  :chartData="item"
                  :chartLeft="20"
                  :color="linearColor[index]"
                  ref="barchart"
        >
        </barChart>
        <barChart class="chart-size"
                  :chartData="categoryDataList[0]"
                  :chartLeft="20"
                  :color="linearColor[0]"
                  ref="barchart"
        >
        </barChart>
      </div>
    </div>
</template>

<script>
  import barChart from './barChart'

  export default {
    name: 'chart',
    components: {
      barChart
    },
    props: {
      categoryDataList: {
        type: Array,
        default: function () {
            return []
        }
      }
    },
    data() {
      const self = this
      return {
        activeChartIndex: 0,
        linearColor: [
          new this.$echarts.graphic.LinearGradient(0, 0, 1, 1, [{
            offset: 0,
            color: '#394FFD' // 0% 处的颜色
          }, {
            offset: 1,
            color: '#0AFFC5' // 100% 处的颜色
          }], false),
          new this.$echarts.graphic.LinearGradient(0, 0, 1, 1, [{
            offset: 0,
            color: '#FFCB14'
          }, {
            offset: 1,
            color: '#0DE4C2'
          }], false),
          new this.$echarts.graphic.LinearGradient(0, 0, 1, 1, [{
            offset: 0,
            color: '#B62A2B'
          }, {
            offset: 1,
            color: '#EBBC15'
          }], false)
        ],
        carouselTimer: null,
        animating: false,
        transitionTimer: null
      }
    },
    watch: {
      categoryDataList(curVal) {

      }
    },
    mounted() {
      this.handleCarousel()
    },
    methods: {
      /**
       * @description 自动轮播
       */
      handleCarousel() {
        this.$nextTick(() => {
          this.carouselTimer = setInterval(() => {
            this.move()
          }, 2000)
        })
      },
      move() {
        let swiper = this.$refs.swiper
        this.activeChartIndex++
        swiper.style.transform = `translate3d(-${this.activeChartIndex * 100}%, 0, 0)`
        swiper.style.transition = 'transform 1s'
        if (this.activeChartIndex === this.categoryDataList.length) {
          this.activeChartIndex = 0
          this.animating = true
          clearTimeout(this.transitionTimer)
          this.transitionTimer = setTimeout(() => {
            swiper.style.transform = 'translate3d(0%, 0, 0)'
            swiper.style.transition = ''
            this.animating = false
          }, 1000)
        }
      },
      // 鼠标移上去停止滚动
      mouseHover() {
        clearInterval(this.carouselTimer)
        this.carouselTimer = null;
      },
      // 鼠标移出后继续滚动
      mouseOut() {
        this.carouselTimer = setInterval(() => {
          this.move()
        }, 2000)
      },
      // 当点击切换的时候的操作
      changeActiveIndex(index) {
        let swiper = this.$refs.swiper
        let interval = 0
        if (this.animating) {
          clearTimeout(this.transitionTimer)
          this.transitionTimer = null
          swiper.style.transform = 'translate3d(-300%, 0, 0)'
          swiper.style.transition = ''
          setTimeout(() => {
            swiper.style.transform = 'translate3d(0%, 0, 0)'
            swiper.style.transition = ''
          }, 0)
          this.animating = false
          interval = 50
        }
        setTimeout(() => {
          clearInterval(this.carouselTimer)
          this.carouselTimer = null;
          this.activeChartIndex = index
          swiper.style.transform = `translate3d(-${this.activeChartIndex * 100}%, 0, 0)`
          swiper.style.transition = 'transform 0.5s'
          this.carouselTimer = setInterval(() => {
            this.move()
          }, 2000)
        }, interval)
      }
    }
  }
</script>

<style scoped lang="less">
    .chart-out-wrapper {
      width: 100%;
      height: 100%;
      overflow: hidden;
      .chart-wrapper {
        display: -webkit-box;
        width: 100%;
        height: 100%;
        .chart-size {
          width: 100%;
          height: 100%;
        }
      }
    }

</style>

都知道,实现无缝轮播,一般都会将第一个节点及其子节点使用cloneNode(true)克隆一份拼接到末尾,但是这样子会有一个问题,它只克隆节点所有属性以及它们的值,但不包括事件,而且也不会随着数据更新而更新(个人认为:可以通过在无缝过渡的时候强制去更新节点的数据,可参考:https://www.jianshu.com/p/fc8df1229b52  虽然我没有实现这个,但是别人贴出来了说明一般情况下是可以的,我是在init部分报错,而且时间较紧,耐心也用完,笔者没办法做下去了==||)。因此,通过显示的克隆节点(也就是直接将数据拼接到后面啦!!),这样就可以解决数据不变的问题

实现无缝轮播的方式有很多,笔者用的是tansition+transform的方式,参考了另一个博客,他的写法会更简单

参考的链接:

https://zhuanlan.zhihu.com/p/32822928

笔者实现如下:

handleCarousel() {
        this.$nextTick(() => {
          this.carouselTimer = setInterval(() => {
            this.move()
          }, 2000)
        })
      },
      move() {
        let swiper = this.$refs.swiper
        this.activeChartIndex++
        swiper.style.transform = `translate3d(-${this.activeChartIndex * 100}%, 0, 0)`
        swiper.style.transition = 'transform 1s'
        if (this.activeChartIndex === this.categoryDataList.length) {
          this.activeChartIndex = 0
          this.animating = true
          clearTimeout(this.transitionTimer) // 当处于过渡时,清除定时器,这个是点击切换页面的点时触发的定时器
          this.transitionTimer = setTimeout(() => { // 当过渡完成后就将第一个tab移至可视区域,看到博客有人建议使用transitionend时间来监听过渡完成的时间,则不用使用setTimout来计算时间
            swiper.style.transform = 'translate3d(0%, 0, 0)'
            swiper.style.transition = ''
            this.animating = false
          }, 1000)
        }
      }

当页面包含有分页器的时候,会产生一个问题:“在transition结束后Timeout切换有个bug,从最后一张(算上过渡区是倒数第二张),以少于transition-duration的时间间隔连点两次,它会切回去。”

笔者的解决方式是使用先触发立即移至最后一页(也就是克隆的那一页),延时将第一页移至可视区域,最后再加延时过渡到点击的那一页,实现如下:

 changeActiveIndex(index) {
        let swiper = this.$refs.swiper
        let interval = 0
        if (this.animating) {
          clearTimeout(this.transitionTimer)
          this.transitionTimer = null
          swiper.style.transform = 'translate3d(-300%, 0, 0)'
          swiper.style.transition = ''
          setTimeout(() => {
            swiper.style.transform = 'translate3d(0%, 0, 0)'
            swiper.style.transition = ''
          }, 0)
          this.animating = false
          interval = 50
        }
        setTimeout(() => {
          clearInterval(this.carouselTimer)
          this.carouselTimer = null;
          this.activeChartIndex = index
          swiper.style.transform = `translate3d(-${this.activeChartIndex * 100}%, 0, 0)`
          swiper.style.transition = 'transform 0.5s'
          this.carouselTimer = setInterval(() => {
            this.move()
          }, 2000)
        }, interval)
      }

文章可能有不正确的地方,希望能够指正,或者提出更好的实现方式,多多交流。

发布了51 篇原创文章 · 获赞 33 · 访问量 9万+

猜你喜欢

转载自blog.csdn.net/shelbyandfxj/article/details/95110990