【总结】微信小程序 - 用动画实现自定义轮播图
最近小程序有个需求要做一个类似轮播的自定义样式,搜了一下插件们,一般都用到了jQuery,但是小程序又不支持操作DOM,所以直接自己卷起袖子干吧。
如果有任何有问题的地方,欢迎各位看官指出,大家一起讨论才能进步地更快XD文章基本流程:
1.效果图
2.实现代码
3.被放弃的提案及理由(TAT)
4.总结
1.首先放实现的效果图
因为需求里只有中间的三张图,所以之后会把旁边两张的opacity调成0,这里为了方便看就留着啦。
2. 代码
a. wxml
这里之前考虑过要使用template,毕竟比较方便。但是每个图片又会再绑定不同的动画效果,所以就直接这样摊大饼展开写了,如果谁有更好的方法,答应我,一定要告诉我,好嘛 :)
<view style="white-space: nowrap;" class="box" bindtouchstart="touchstart" bindtouchmove="touchmove" bindtouchend="touchend">
<view class="club" animation="{{animation1}}" bindtap="scrollLeft">
<image src="{{clubs[0].image}}"/>
<text>{{clubs[0].name}}</text>
</view>
<view class="club" animation="{{animation2}}" bindtap="scrollLeft">
<image src="{{clubs[1].image}}"/>
<text>{{clubs[1].name}}</text>
</view>
<view class="club" animation="{{animation3}}">
<image src="{{clubs[2].image}}"/>
<text>{{clubs[2].name}}</text>
</view>
<view class="club" animation="{{animation4}}" bindtap="scrollRight">
<image src="{{clubs[3].image}}"/>
<text>{{clubs[3].name}}</text>
</view>
<view class="club" animation="{{animation5}}" bindtap="scrollRight">
<image src="{{clubs[4].image}}"/>
<text>{{clubs[4].name}}</text>
</view>
</view>
b. wxss
这里因为没有涉及到图片互相遮盖的问题,所以大胆地使用了opacity,但是如果做成了叠加效果的话,我的方法是使用伪类:after或者:before在图片上加一个白色背景色带透明度的一层。
有关css的transform3d可以参考【这篇简单易懂的文章】
transform2d可以参考【这篇附带演示的文章】
.box {
height: 340rpx;
z-index: 0;
margin: 50rpx 0;
}
.box .club {
height: 140rpx;
width: 140rpx;
position: relative;
display: inline-block;
}
.club image {
height: 140rpx;
width: 140rpx;
}
.club text {
display: block;
width: 100%;
font-size: 24rpx;
line-height: 40rpx;
text-align: center;
}
.box .club:nth-child(1) {
transform: scale(0.8, 0.8) translateX(-120rpx);
opacity: 0.2;
z-index: 10;
}
.box .club:nth-child(2) {
transform: scale(1,1) translateX(-80rpx);
opacity: 0.5;
z-index: 100;
}
.box .club:nth-child(3) {
transform: scale(1.4,1.4);
z-index: 1000;
}
.box .club:nth-child(4) {
transform: scale(1,1) translateX(80rpx);
opacity: 0.5;
z-index: 100;
}
.box .club:nth-child(5) {
transform: scale(0.8, 0.8) translateX(120rpx);
opacity: 0.2;
z-index: 10;
}
.box .club:nth-child(1) text,
.box .club:nth-child(2) text,
.box .club:nth-child(4) text,
.box .club:nth-child(5) text{
visibility: hidden;
}
c. js
①首先,要通过js的touchstart,touchmove和touchend事件判断手指的左右滑动。
此处参考了【这篇文章】
//触摸开始事件
touchstart: function(e) {
console.log(e.touches[0].pageX);
this.data.touchDot = e.touches[0].pageX;
var that = this;
this.data.interval = setInterval(function(){
that.data.time+=1;
},100);
},
//触摸移动事件
touchmove: function(e) {
let touchMove = e.touches[0].pageX;
let touchDot = this.data.touchDot;
let time = this.data.time;
console.log("touchMove: " + touchMove + ", touchDot: " + touchDot + ", diff: " + (touchMove - touchDot));
//向左滑动
if(touchMove - touchDot <= -40 && time<10 &&!this.data.done) {
console.log("向左滑动");
this.data.done = true;
this.scrollLeft();
}
//向右滑动
if (touchMove - touchDot >= 40 && time < 10 && !this.data.done) {
console.log("向右滑动");
this.data.done = true;
this.scrollRight();
}
},
//触摸结束事件
touchend: function(e) {
clearInterval(this.data.interval);
this.data.time = 0;
this.data.done = false;
}
②然后写scrollLeft和scrollRight事件
这里参考了【这篇文章】中设置动画的方式。
主要思想:在一定的时间(duration)之内,让图片向左(/右)移动,并伴以适当的scale以及opacity变换。然后再在0s之内完成两件事:一个是瞬间使刚才移动的图片回归原位(scale和opacity自然也不必说),还有一个是在图片的队列中shift(/pop)出一个来再push(/unshift)进去,并且在0s内setData。这样从视觉上看起来就是图片向左(/右)滑动了。
此处需要注意的是:图像动画的duration最好大于瞬间还原以及set数组的定时时间。如果他们的时间都设置为同样的话(如300),在滑动中肉眼能够看到明显的闪动(由于前后的图片切换)。
//向左滑动事件
scrollLeft(){
var animation1 = wx.createAnimation({
duration: 300,
timingFunction: "linear",
delay: 0
})
var animation2 = wx.createAnimation({
duration: 300,
timingFunction: "linear",
delay: 0
})
var animation3 = wx.createAnimation({
duration: 300,
timingFunction: "linear",
delay: 0
})
var animation4 = wx.createAnimation({
duration: 300,
timingFunction: "linear",
delay: 0
})
var animation5 = wx.createAnimation({
duration: 300,
timingFunction: "linear",
delay: 0
})
this.animation1 = animation1;
this.animation2 = animation2;
this.animation3 = animation3;
this.animation4 = animation4;
this.animation5 = animation5;
this.animation1.translateX(-60).opacity(0).step();
this.animation2.translateX(-140).opacity(0.5).scale(0.8,0.8).step();
this.animation3.translateX(-110).opacity(0.5).scale(1,1).step();
this.animation4.translateX(-70).opacity(1).scale(1.4,1.4).step();
this.animation5.translateX(-30).opacity(0.5).scale(1,1).step();
this.setData({
animation1: animation1.export(),
animation2: animation2.export(),
animation3: animation3.export(),
animation4: animation4.export(),
animation5: animation5.export()
})
var that = this;
setTimeout(function () {
that.animation1.translateX(-50).opacity(0.2).scale(0.8, 0.8).step({ duration: 0, timingFunction: 'linear'});
that.animation2.translateX(-40).opacity(0.5).scale(1, 1).step({ duration: 0, timingFunction: 'linear' });
that.animation3.translateX(0).opacity(1).scale(1.4, 1.4).step({ duration: 0, timingFunction: 'linear' });
that.animation4.translateX(40).opacity(0.5).scale(1, 1).step({ duration: 0, timingFunction: 'linear' });
that.animation5.translateX(50).opacity(0.2).scale(0.8, 0.8).step({ duration: 0, timingFunction: 'linear' });
that.setData({
animation1: animation1.export(),
animation2: animation2.export(),
animation3: animation3.export(),
animation4: animation4.export(),
animation5: animation5.export()
})
}.bind(this), 195)
let array = this.data.clubs;
let shift = array.shift();
array.push(shift);
setTimeout(function () {
this.setData({
clubs: array
})
}.bind(this), 195)
},
//向右滑动事件
scrollRight() {
var animation1 = wx.createAnimation({
duration: 300,
timingFunction: "linear",
delay: 0
})
var animation2 = wx.createAnimation({
duration: 300,
timingFunction: "linear",
delay: 0
})
var animation3 = wx.createAnimation({
duration: 300,
timingFunction: "linear",
delay: 0
})
var animation4 = wx.createAnimation({
duration: 300,
timingFunction: "linear",
delay: 0
})
var animation5 = wx.createAnimation({
duration: 300,
timingFunction: "linear",
delay: 0
})
this.animation1 = animation1;
this.animation2 = animation2;
this.animation3 = animation3;
this.animation4 = animation4;
this.animation5 = animation5;
this.animation1.translateX(30).opacity(0.5).scale(1,1).step();
this.animation2.translateX(70).opacity(1).scale(1.4, 1.4).step();
this.animation3.translateX(110).opacity(0.5).scale(1, 1).step();
this.animation4.translateX(120).opacity(0.2).scale(0.8, 0.8).step();
this.animation5.translateX(130).opacity(0).step();
this.setData({
animation1: animation1.export(),
animation2: animation2.export(),
animation3: animation3.export(),
animation4: animation4.export(),
animation5: animation5.export()
})
var that = this;
setTimeout(function () {
that.animation1.translateX(-50).opacity(0.2).scale(0.8, 0.8).step({ duration: 0, timingFunction: 'linear' });
that.animation2.translateX(-40).opacity(0.5).scale(1, 1).step({ duration: 0, timingFunction: 'linear' });
that.animation3.translateX(0).opacity(1).scale(1.4, 1.4).step({ duration: 0, timingFunction: 'linear' });
that.animation4.translateX(40).opacity(0.5).scale(1, 1).step({ duration: 0, timingFunction: 'linear' });
that.animation5.translateX(50).opacity(0.2).scale(0.8, 0.8).step({ duration: 0, timingFunction: 'linear' });
that.setData({
animation1: animation1.export(),
animation2: animation2.export(),
animation3: animation3.export(),
animation4: animation4.export(),
animation5: animation5.export()
})
}.bind(this), 195)
let array = this.data.clubs;
let pop = array.pop();
array.unshift(pop);
setTimeout(function () {
this.setData({
clubs: array
})
}.bind(this), 195)
}
3. 被放弃的提案
原本的需求是实现一个类似这样的效果(不要笑我用了opacity,解决办法我已经写在了上边的css部分里):
但是当我满心欢喜,实现了静态效果,准备做动画的时候,发现小程序竟然不支持perspective!!!!!!!
啥?你问什么是perspective?来看【这篇】或者【上边wxss中提到的3d的这篇】吧
简单说perspective就是透视,如果没有透视,那么无论你怎么翻转怎么rotate,他都是一个矩形,或者一个平行四边形(skew),而不会变成一个梯形,就是没有近大远小的效果。perspective就相当于z轴的大小,越大透视效果越强。
如图(左边的就是小程序的rotateY):
//实现透视状的css代码
.box .club:nth-child(1){
transform-origin: 100% 50%;
transform: perspective(600rpx) rotateY(45deg) translateX(420rpx) scale(1.5, 1.3);
z-index: 0;
opacity: 0.5;
}
.box .club:nth-child(2){
transform-origin: 100% 50%;
transform: perspective(600rpx) rotateY(45deg) translateX(200rpx) scale(1.3, 1);
opacity: 0.5;
z-index: 10;
}
.box .club:nth-child(3) {
transform-origin: 100% 50%;
transform: perspective(600rpx) rotateY(45deg) translateX(60rpx) scale(1.1, 0.9);
opacity: 0.5;
z-index: 100;
}
.box .club:nth-child(4) {
transform: perspective(600rpx) rotateY(0deg);
z-index: 1000;
}
.box .club:nth-child(5){
transform-origin: 0 50%;
transform: perspective(600rpx) rotateY(-45deg) translateX(-60rpx) scale(1.1, 0.9);
opacity: 0.5;
z-index: 100;
}
.box .club:nth-child(6){
transform-origin: 0 50%;
transform: perspective(600rpx) rotateY(-45deg) translateX(-200rpx) scale(1.3, 1);
opacity: 0.5;
z-index: 10;
}
.box .club:nth-child(7) {
transform-origin: 0 50%;
transform: perspective(600rpx) rotateY(-45deg) translateX(-420rpx) scale(1.5, 1.3);
opacity: 0.5;
z-index: 0;
}
无动画实现效果:
4. 总结
通过这次补了一下css的transform的知识,还接触了下小程序的动画感觉还蛮不错的。虽然折腾了好几天,但是感觉很有意义!
感谢阅读
祝各位都有美好的一天 have a nice day~~~
上一篇: Spring如何解决循环依赖