目录
一 场景
需要实现小程序的轮播图。目标如下
要求:图片数量可变(最少3个,最多不限),有动画效果
效果预览:
二 思路
查看小程序api:
问题1,每一个animations都绑定在一个view上,不能遍历获取。
所以对不确定数量的图片时,不能保证每个图片都绑定一个animations。
所以这里定义5个容器(可以看见3个,剩余两个隐藏在后面),用着5个容器装图片,每次滚动容器,容器带动图片,然后更新图片。
问题2,偏移量计算
有5个容器,每个容器动画实现的时候的偏移量计算是多少?
从图中可以看出,一共3个可视位置,每个位置对应的位移量分别为0,40,100(这里是百分比单位)
所以5个容器在三个位置的位移量分别为0(or 40 or 100)- 100 * index
三 实现
1.wxss
.video-box {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 30rpx;
}
.icon {
width:24px;
height:24px;
}
.box {
width: 90%;
z-index: 0;
white-space: nowrap;
display: flex;
flex-direction: row;
}
.box .club {
width: 335rpx;
position: relative;
}
.club image {
height: 370rpx;
width: 335rpx;
}
.club text {
display: block;
width: 100%;
font-size: 24rpx;
line-height: 40rpx;
text-align: center;
}
.box .club:nth-child(1) {
transform-origin: center center;
}
.box .club:nth-child(2) {
transform-origin: center center;
}
.box .club:nth-child(3) {
transform-origin: center center;
}
2.wxml
<view class='video-box'>
<view bindtap="scrollLeft"><image class='icon' src='../../images/left.png' mode='widthFit'></image></view>
<view class="box" bindtouchstart="touchstart" bindtouchmove="touchmove" bindtouchend="touchend"
>
<block>
<view class="club" animation="{{animation1}}" style='z-index:{{zindex[0]}};opacity:{{opacities[0]}};'>
<image src="{{container[0].image}}"/>
<text>{{container[0].name}}</text>
</view>
<view class="club" animation="{{animation2}}" style='z-index:{{zindex[1]}};opacity:{{opacities[1]}};'>
<image src="{{container[1].image}}"/>
<text>{{container[1].name}}</text>
</view>
<view class="club" animation="{{animation3}}" style='z-index:{{zindex[2]}};opacity:{{opacities[2]}};'>
<image src="{{container[2].image}}"/>
<text>{{container[2].name}}</text>
</view>
<view class="club" animation="{{animation4}}" style='z-index:{{zindex[3]}};opacity:{{opacities[3]}};'>
<image src="{{container[3].image}}"/>
<text>{{container[3].name}}</text>
</view>
<view class="club" animation="{{animation5}}" style='z-index:{{zindex[4]}};opacity:{{opacities[4]}};'>
<image src="{{container[4].image}}"/>
<text>{{container[4].name}}</text>
</view>
</block>
</view>
<view bindtap="scrollRight"><image class='icon' src='../../images/right.png'></image></view>
</view>
<view class="container">
<view animation="{{animation}}" class="view">我在做动画</view>
</view>
3.js
a.数据准备
data: {
clubs: [], //原始数据
animations: [],
touchDot: '',
done: false,
time: 0,
container: [], //记录当前5个位置为哪5个item,理解为5个容器
curPos: 2, //记录当前显示位置是第几个容器(从0开始)
zindex: [0, 10, 100, 10, 0], //与container中的对应
curIndex:1,//从显示位置的item在clubs中的index
postions: [0,1,2,3,4],//container中5个容器所在位置
opacities:[0,0.8,1,0.8,0],
},
b.onload初始化
onLoad: function() {
var data = [{ //原始数据,可为动态
image: '../../images/a.png',
name: '1美女'
},
{
image: '../../images/b.png',
name: '2美女'
},
{
image: '../../images/c.png',
name: '3美女'
}, {
image: '../../images/d.png',
name: '4美女'
},{
image: '../../images/e.png',
name: '5美女'
}
]
this.setData({
clubs: data
})
//给5个容器赋值clubs0,1,2去到pos
//pos的0,1,2,3,4为clubs的last,0,1,2,2+1
//即pos的2(显示)位置是clubs的1位置
this.setPos(2,1);
//初始化到正确的位置
var animation1 = wx.createAnimation({
duration: 500,
timingFunction: "ease",
delay: 0
})
var animation2 = wx.createAnimation({
duration: 500,
timingFunction: "ease",
delay: 0
})
var animation3 = wx.createAnimation({
duration: 500,
timingFunction: "ease",
delay: 0
})
var animation4 = wx.createAnimation({
duration: 500,
timingFunction: "ease",
delay: 0
})
var animation5 = wx.createAnimation({
duration: 500,
timingFunction: "ease",
delay: 0
})
this.animation1 = animation1;
this.animation2 = animation2;
this.animation3 = animation3;
this.animation4 = animation4;
this.animation5 = animation5;
this.animation1.translateX('0%').opacity(0).scale(0).step();
this.animation2.translateX('-100%').opacity(0.4).scale(0.8).step();
this.animation3.translateX('-160%').opacity(1).scale(1).step();
this.animation4.translateX('-200%').opacity(0.4).scale(0.8).step();
this.animation5.translateX('-300%').opacity(0).scale(0).step();
this.setData({
animation1: animation1.export(),
animation2: animation2.export(),
animation3: animation3.export(),
animation4: animation4.export(),
animation5: animation5.export()
})
},
c.一些方法
//设置位置
/**
* pos:显示位置在container中的位置
* index:显示位置的clubs索引
*/
setPos: function(pos,index) {
let container = [];
let p2 = pos;
let p1 = this.findPrePos(p2);
let p0 = this.findPrePos(p1);
let p3 = this.findNextPos(p2);
let p4 = this.findNextPos(p3);
let i2 = index;
let i1 = this.findPreIndex(i2);
let i0 = this.findPreIndex(i1);
let i3 = this.findNextIndex(i2);
let i4 = this.findNextIndex(i3);
container[p0] = this.data.clubs[i0];
container[p1] = this.data.clubs[i1];
container[p2] = this.data.clubs[i2];
container[p3] = this.data.clubs[i3];
container[p4] = this.data.clubs[i4];
this.setData({
container
})
},
/**
* container中的位置
*/
findNextPos: function(pos) {
if (pos != 4) {
return pos + 1;
}
return 0;
},
findPrePos: function(pos) {
if (pos != 0) {
return pos - 1;
}
return 4;
},
/**
* newPos:新的他要到的的位置
*/
findNewDistance(newPos,index) {
let newDistances = [];
switch (newPos) {
case 0:
newDistances = [0 - 100 * index + '%', 0, 0];
break;
case 1:
newDistances = [0 - 100 * index + '%', 0.4, 0.8];
break;
case 2:
newDistances = [40 - 100 * index + '%', 1, 1];
break;
case 3:
newDistances = [100 - 100 * index + '%', 0.4, 0.8];
break;
case 4:
newDistances = [100 - 100 * index + '%', 0, 0];
break;
}
return newDistances;
},
setNewZindex(newPos) {
let zindexes = [];
zindexes[newPos] = 100;
let nextPos = this.findNextPos(newPos);
zindexes[nextPos] = 10;
let nnextPos = this.findNextPos(nextPos);
zindexes[nnextPos] = 0;
let prePos = this.findPrePos(newPos);
zindexes[prePos] = 10;
let pprePos = this.findPrePos(prePos);
zindexes[pprePos] = 0;
this.setData({
zindex: zindexes
})
},
findNextIndex(index) {
if (index != this.data.clubs.length - 1) {
return index + 1;
}
return 0;
},
findPreIndex(index) {
if (index != 0) {
return index - 1;
}
return this.data.clubs.length - 1;
}
d.右划事件
//向右滑动事件
scrollRight() {
let container = this.data.container;
let oldPos = this.data.curPos;
let newPos = oldPos == 0 ? 4 : oldPos - 1;
let newIndex = this.findPreIndex(this.data.curIndex);
//先滑动,再赋值
var animation1 = wx.createAnimation({
duration: 500,
timingFunction: "ease",
delay: 0
})
var animation2 = wx.createAnimation({
duration: 500,
timingFunction: "ease",
delay: 0
})
var animation3 = wx.createAnimation({
duration: 500,
timingFunction: "ease",
delay: 0
})
var animation4 = wx.createAnimation({
duration: 500,
timingFunction: "ease",
delay: 0
})
var animation5 = wx.createAnimation({
duration: 500,
timingFunction: "ease",
delay: 0
})
this.animation1 = animation1;
this.animation2 = animation2;
this.animation3 = animation3;
this.animation4 = animation4;
this.animation5 = animation5;
let distances = [];
let newPostions = [];
let newOpacities = [];
//用新位置找位移量
for (let i = 0; i < container.length; i++) {
let newPos = this.findNextPos(this.data.postions[i]);
let distance = this.findNewDistance(newPos, i);
distances.push(distance);
newPostions.push(newPos);
newOpacities.push(distance[1]);
}
this.animation1.translateX(distances[0][0]).opacity(distances[0][1]).scale(distances[0][2]).step();
this.animation2.translateX(distances[1][0]).opacity(distances[1][1]).scale(distances[1][2]).step();
this.animation3.translateX(distances[2][0]).opacity(distances[2][1]).scale(distances[2][2]).step();
this.animation4.translateX(distances[3][0]).opacity(distances[3][1]).scale(distances[3][2]).step();
this.animation5.translateX(distances[4][0]).opacity(distances[4][1]).scale(distances[4][2]).step();
this.setData({
opacities: newOpacities,
postions: newPostions,
animation1: animation1.export(),
animation2: animation2.export(),
animation3: animation3.export(),
animation4: animation4.export(),
animation5: animation5.export()
})
//赋值
this.setPos(newPos, newIndex)
this.setNewZindex(newPos)
this.setData({
curPos: newPos,
curIndex:newIndex,
})
},
总结:
滑动触发借鉴了https://blog.csdn.net/sinat_22014829/article/details/76539612这篇博客,但是在图片数量不确定的情况下感觉有些不太够用,于是自己又写了一个。有些借鉴的代码没有写出来。整个项目可以到https://github.com/xing3gg/wx_littleProject_animation上去下载,如果有所启发记得打星哟!