继上个卡片轮播图,这次又遇到了没写过的轮播方式——单侧堆叠轮播图,整体样式保持不变,点击切换有移动、放大、淡出、淡入等动画效果,网上找了一大堆也没有符合要求的只能手写了,下面是UI图:
实现思路:
1.将list数组[1,2,3]前后各追加1个item,然后用flex布局将card并排展示:
2.设置每个card的左间距和scale大小,隐藏第一个和最后一个:
3.点击左右切换时处理list数组
if (type == 1) { //下一个
this.swiperList.push(this.swiperList[2])
this.swiperList.splice(0, 1)
} else { //上一个
this.swiperList.unshift(this.swiperList[this.swiperList.length - 3])
this.swiperList.pop()
}
4.最后使用css:animation添加动画效果就可以了
.swiper-box .swiper-list.swleft .swiper-item:nth-child(2) {
animation: fadel 0.4s ease-in-out 1; /* 淡入淡出动画持续1秒,使用ease-in-out速度曲线,播放1次 */
}
@keyframes fadel {
0% { opacity: 1;left: 0; }
100% { opacity: 0;left: -60px; }
}
...
效果图:
由于项目要求的是固定3个card这里暂时只做了3个,其它数量可以自行修改,下面上完整代码(可以直接运行):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://unpkg.com/vue@2/dist/vue.js"></script>
</head>
<body>
<div id="app">
<div class="swiper-box">
<div class="swiper-btn">
<button @click="changeSwiper(-1)">←</button>
<button @click="changeSwiper(1)">→</button>
</div>
<div class="swiper-list" :class="{swleft, swright}">
<div class="swiper-item" v-for="(item, index) in swiperList" :key="index"
:style="{backgroundColor: colorMap[item.value], 'z-index': 999-index, transform: `scale(${1-(index-1)*0.1})`}">
<h3>{{ item.title }}</h3>
</div>
</div>
</div>
</div>
</body>
</html>
<script>
new Vue({
el: '#app',
data() {
return {
tabList: [
{ title: '111',value: '0' },
{ title: '222',value: '1' },
{ title: '333',value: '2' },
],
swiperList: [],
clear: null,
colorMap: {
0: 'green',
1: 'pink',
2: 'yellow',
},
swleft: false,
swright: false,
};
},
mounted() {
const list = [
...this.tabList.slice(-1),
...this.tabList,
...this.tabList.slice(0, 1)
]
this.swiperList = list
},
methods: {
debounce(delay) {
if (this.clear) {
return false
}
this.clear = setTimeout(() => {
this.clear = null
}, delay)
return true
},
changeSwiper(type) {
// 防抖
if (!this.debounce(360)) {
return
}
if (type == 1) { //下一个
this.swleft = true
setTimeout(() => {
this.swleft = false
this.swiperList.push(this.swiperList[2])
this.swiperList.splice(0, 1)
}, 350);
} else { //上一个
this.swright = true
setTimeout(() => {
this.swright = false
this.swiperList.unshift(this.swiperList[this.swiperList.length - 3])
this.swiperList.pop()
}, 350);
}
},
}
})
</script>
<style>
.swiper-box {
position: relative;
overflow: hidden;
}
.swiper-btn{
margin: 20px;
}
.swiper-box .swiper-list {
display: flex;
height: 400px;
overflow: hidden;
}
.swiper-box .swiper-list.swleft .swiper-item:nth-child(2) {
animation: fadel 0.4s ease-in-out 1; /* 淡入淡出动画持续1秒,使用ease-in-out速度曲线,播放1次 */
}
.swiper-box .swiper-list.swleft .swiper-item:nth-child(3) {
animation: fadel2 0.4s ease-in-out 1;
}
.swiper-box .swiper-list.swleft .swiper-item:nth-child(4) {
animation: fadel3 0.4s ease-in-out 1;
}
.swiper-box .swiper-list.swleft .swiper-item:nth-child(5) {
animation: fadel4 0.4s ease-in-out 1;
}
@keyframes fadel {
0% { opacity: 1;left: 0; }
100% { opacity: 0;left: -60px; }
}
@keyframes fadel2 {
0% { left: 0; }
100% { left: -60px;transform: scale(1); }
}
@keyframes fadel3 {
0% { left: 0; }
100% { left: -60px;transform: scale(0.9); }
}
@keyframes fadel4 {
0% { left: 0; }
100% { left: -60px; opacity: 1;transform: scale(0.8); }
}
.swiper-box .swiper-list.swright .swiper-item:nth-child(1) {
animation: fader 0.4s ease-in-out 1;
}
.swiper-box .swiper-list.swright .swiper-item:nth-child(2) {
animation: fader2 0.4s ease-in-out 1;
}
.swiper-box .swiper-list.swright .swiper-item:nth-child(3) {
animation: fader3 0.4s ease-in-out 1;
}
.swiper-box .swiper-list.swright .swiper-item:nth-child(4) {
animation: fader4 0.4s ease-in-out 1;
}
@keyframes fader {
0% { opacity: 0;left: 0; }
100% { opacity: 1;left: 60px;transform: scale(1); }
}
@keyframes fader2 {
0% { left: 0; }
100% { left: 60px;transform: scale(0.9); }
}
@keyframes fader3 {
0% { left: 0; }
100% { left: 60px;transform: scale(0.8); }
}
@keyframes fader4 {
0% { left: 0; }
100% { left: 60px; opacity: 0;transform: scale(0.7); }
}
.swiper-box .swiper-list .swiper-item {
display: flex;
align-content: center;
flex-wrap: wrap;
border-radius: 20px;
padding: 0 95px;
background: #ccc;
width: 600px;
height: 400px;
box-sizing: border-box;
position: relative;
}
.swiper-box .swiper-list .swiper-item+.swiper-item {
margin-left: -540px;
}
.swiper-box .swiper-list .swiper-item:last-child {
opacity: 0;
}
.swiper-box .swiper-list .swiper-item:first-child {
opacity: 0;
}
</style>