gsap 补间动画列表两种高度环绕旋转动画效果

vue yekong

之前我们通过 gsap 补间动画 插件实现了 gsap 补间动画列表环绕旋转动画效果,客户看了以后增加了一项要求,就是动画中的两行高度是不一样的,上面的高一些,下面的矮一些,这就需要我们对代码进行调整了。

gsap 补间动画列表环绕旋转动画效果

效果演示

效果要求:

列表上下两种高度,上面的占比60%下面的占比40%

实现思路:

我们设置两个变量,一个60% 一个40%以便于后期调整。

父组件

首先写一个父组件,用来渲染列表,添加顺时针和逆时针的点击事件。然后添加一个基数,通过监听这个基数的变化来触发动画。

<template>
  <div class="items">
    <div class="listMain">
      <div class="infoleft" @click="getPrev">左侧</div>
      <div class="list">
        <item ref="item" :isNext="isNext" :base="base" :index="index" :list="list" v-for="(item,index) in list"
              :key="index"></item>
      </div>
      <div class="infoleft" @click="getNext">右侧</div>
    </div>
  </div>
</template>

<script>

import item from './item.vue'

export default {
  name: "item1",
  data() {
    return {
      height: 0,
      base: 0,
      isNext: true,
      list: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    }
  },
  components: {item},
  watch: {},
  mounted() {
    this.base = 1000 * this.list.length
  },
  methods: {
    getNext() {
      this.base = this.base + 1
      this.isNext = true
    },
    getPrev() {
      this.base = this.base - 1
      this.isNext = false
    },
  },
}
</script>

<style lang="scss" scoped>
.items {
  position: relative;
  width: 100%;
  height: 100%;
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: nowrap;
  flex-direction: row;
  align-content: flex-start;

  .listMain {
    position: relative;
    width: 100%;
    height: 100%;
    display: flex;
    justify-content: space-between;
    align-items: center;
    flex-wrap: nowrap;
    flex-direction: row;
    align-content: flex-start;

    .infoleft {
      width: 50px;
      position: relative;
      height: 100%;
      background: red;
      display: flex;
      justify-content: center;
      align-items: center;
      flex-wrap: nowrap;
      flex-direction: row;
      align-content: flex-start;
    }

    .list {
      position: relative;
      width: calc(100% - 100px);
      height: 100%;
    }
  }
}
</style>

子组件

我们在之前的代码基础上调整组件上下的间距以及组件高度。

<template>
  <div class="listItem" ref="listItem" :style="{left:left+'%',top:top+'%'}">
    <div class="listItems">
      <!--      <p>l:{{ left }}</p>-->
      <p>b:{{ baseNum }}</p>
      <p>i:{{ index }}</p></div>
  </div>
</template>

<script>
import gsap from 'gsap'

export default {
  name: "item",
  data() {
    return {
      runBackwards: false,
      isFirst: 0,
      height1: '60%',
      height2: '40%'
    }
  },
  props: {
    index: {
      type: Number,
      default() {
        return 0;
      }
    },
    base: {
      type: Number,
      default() {
        return 0;
      }
    },
    isNext: {
      type: Boolean,
      default() {
        return true;
      }
    },
    list: {
      type: Array,
      default() {
        return [];
      }
    },
  },
  watch: {
    base(from, to) {
      console.log(this.base)
      if (this.isNext) {
        this.getNext()
      } else {
        this.getPrev()
      }
    },
  },
  computed: {
    left: function () {
      var left = 0
      var length = (this.list.length) / 2
      if (this.index < length) {
        left = this.index * (100 / length)
      } else {
        left = (this.list.length - 1 - this.index) * (100 / length)
      }
      return left
    },
    top: function () {
      var top = 0
      var length = (this.list.length) / 2
      if (this.index < length) {
        top = 0
      } else {
        top = 50
      }
      return top
    },
    baseNum: function () {
      var baseNum = ((Math.abs(this.base) + this.index) % this.list.length)
      return baseNum
    },
    baseNum2: function () {
      var baseNum = ((Math.abs(this.base) + this.index) % this.list.length)
      return baseNum
    },
  },
  methods: {
    getNext() {
      var that = this;
      // 从下到上
      if (this.baseNum == 0) {
        gsap.fromTo(this.$refs.listItem, {
          top: this.$refs.listItem.offsetHeight + 'px',
          left: '0%',
          height: this.height2
        }, {
          duration: 1,
          top: '0%',
          left: '0%',
          height: this.height1
        });
      } else if (this.baseNum < (this.list.length) / 2 && this.baseNum > 0) {
        // 从左到右的动画
        gsap.fromTo(this.$refs.listItem, {
          left: this.$refs.listItem.offsetWidth * (this.baseNum - 1) + 'px',
          top: 0,
          height: this.height1
        }, {
          duration: 1,
          top: 0,
          height: this.height1,
          left: this.$refs.listItem.offsetWidth * (this.baseNum) + 'px',
        });
      } else if (this.baseNum == (this.list.length) / 2) {
        // 从上到下的动画
        gsap.fromTo(this.$refs.listItem, {
          top: 0,
          left: '80%',
          height: this.height1
        }, {
          duration: 1,
          left: '80%',
          height: this.height2,
          top: this.height1,
        });
      } else if (this.baseNum > (this.list.length) / 2) {
        // 从右到左的动画
        gsap.fromTo(this.$refs.listItem, {
          left: this.$refs.listItem.offsetWidth * ((this.list.length) - this.baseNum) + 'px',
          top: this.height1,
          height: this.height2,
        }, {
          duration: 1,
          height: this.height2,
          left: this.$refs.listItem.offsetWidth * ((this.list.length) - this.baseNum - 1) + 'px',
          top: this.height1,
        });
      }
    },

    getPrev() {
      var that = this;
      console.log('index:' + this.index + ':' + this.baseNum2)
      console.log('baseNum2')
      // 从上到下
      if (this.baseNum2 == 0) {
        gsap.fromTo(this.$refs.listItem, {
          top: '0%',
          left: '0%',
          height: this.height1,
        }, {
          duration: 1,
          top: this.height1,
          left: '0%',
          height: this.height2,
        });
      } else if (this.baseNum2 < (this.list.length) / 2 && this.baseNum2 > 0) {
        // 从右到左
        gsap.fromTo(this.$refs.listItem, {
          left: this.$refs.listItem.offsetWidth * (this.baseNum2) + 'px',
          top: 0,
          height: this.height1,
        }, {
          duration: 1,
          top: 0,
          height: this.height1,
          left: this.$refs.listItem.offsetWidth * (this.baseNum2 - 1) + 'px',
        });
      } else if (this.baseNum2 == (this.list.length) / 2) {
        // 从下到上
        gsap.fromTo(this.$refs.listItem, {
          left: '80%',
          height: this.height2,
          top: this.height1,
        }, {
          left: '80%',
          duration: 1,
          height: this.height1,
          top: 0,
        });
      } else if (this.baseNum2 > (this.list.length) / 2) {
        // 从左到右
        gsap.fromTo(this.$refs.listItem, {
          top: this.height1,
          height: this.height2,
          left: this.$refs.listItem.offsetWidth * ((this.list.length) - this.baseNum2 - 1) + 'px',
        }, {
          duration: 1,
          height: this.height2,
          left: this.$refs.listItem.offsetWidth * ((this.list.length) - this.baseNum2) + 'px',
          top: this.height1,
        });
      }
    },
  },
}
</script>

<style lang="scss" scoped>
.listItem {
  width: 20%;
  height: 50%;
  position: absolute;
  top: 0;
  left: 0;
  display: flex;
  justify-content: center;
  align-items: center;
  flex-wrap: nowrap;
  flex-direction: row;
  align-content: flex-start;

  .listItems {
    position: relative;
    width: 80%;
    height: 80%;
    background: red;
    display: flex;
    justify-content: center;
    align-items: center;
    flex-wrap: nowrap;
    flex-direction: column;
    align-content: flex-start;
    font-size: 40px;
    color: green;
  }

}

.listItem2 {
  height: 30%;
}

.greens {
  background: green !important;
}
</style>

至此,列表环绕旋转动画效果不同高度效果就实现了。

喜欢