之前我们通过 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>
至此,列表环绕旋转动画效果不同高度效果就实现了。