ps:本次開發(fā)基于wepy框架
由于最近接到一個(gè)需求--抽獎(jiǎng)活動(dòng);
翻牌打亂活動(dòng)抽獎(jiǎng)活動(dòng),大概需求是這樣的,九宮格卡牌,先正面展示所有獎(jiǎng)品,然后卡牌翻轉(zhuǎn),打亂排序,點(diǎn)擊卡牌,然后抽獎(jiǎng)。
這個(gè)需求本身其實(shí)不難,主要是分為三步;
我們先在dom中渲染9個(gè)卡牌。
<view class="card-module">
<view class="card {{showClass ? 'change' : ''}}>
<view class="front card-item">{{cardItem.front}}</view>
<view class="back card-item">{{cardItem.back}}</view>
</view>
</repeat>
</view>
|
在數(shù)據(jù)中生成模擬卡牌數(shù)據(jù)
cardData: [
{
animationData: {},
front: '正面1',
back: '反面1'
},
...
...
{
animationData: {},
front: '正面9',
back: '反面9'
}
],
showClass: false,
|
在樣式中把卡牌的基本樣式渲染出來(lái)
.card-module{
padding: 45rpx;
display: flex;
flex-direction: row;
flex-wrap: wrap;
transform:translate3d(0,0,0);
.card{
width: 200rpx;
height: 200rpx;
line-height: 200rpx;
text-align: center;
color: #fff;
margin: 10rpx;
position:relative;
overflow:hidden;
.card-item{
position:absolute;
left:0;
top:0;
width:100%;
height:100%;
transition:all .5s ease-in-out;
transform-style:preserve-3d;
backface-visibility:hidden;
box-sizing:border-box;
}
.front{
background-color: red;
transform: rotateY(0deg);
z-index:2;
}
.back{
background-color: #009fff;
transform: rotateY(180deg);
z-index:1;
}
}
.card.change{
.front{
z-index:1;
transform: rotateY(180deg);
}
.back{
z-index:2;
transform: rotateY(0deg);
}
}
}
|
效果如下
這里有些css屬性可能需要大部補(bǔ)充學(xué)習(xí)一下
css3 backface-visibility 屬性
定義和用法 backface-visibility 屬性定義當(dāng)元素不面向屏幕時(shí)是否可見(jiàn)。 如果在旋轉(zhuǎn)元素不希望看到其背面時(shí),該屬性很有用。
CSS3 perspective 屬性
perspective 屬性定義 3D 元素距視圖的距離,以像素計(jì)。該屬性允許您改變 3D 元素查看 3D 元素的視圖。 當(dāng)為元素定義 perspective 屬性時(shí),其子元素會(huì)獲得透視效果,而不是元素本身。
由于業(yè)務(wù)上是抽獎(jiǎng)使用的,所以選擇的方案是:翻轉(zhuǎn)后,卡牌收回到中間的卡牌中間,然后再讓卡牌回到原來(lái)的位置。 關(guān)于小程序的原生框架有支持的動(dòng)畫接口,若不了解的請(qǐng)前往: developers.weixin.qq.com/miniprogram… 在對(duì)動(dòng)畫有基本了解之后,我們可以開始在翻轉(zhuǎn)的基礎(chǔ)上加上打亂的動(dòng)畫了 微信小程序的動(dòng)畫接口使用方式是在dom對(duì)象上面加上animation對(duì)象。 dom
<view class="card-module">
<view class="card {{showClass ? 'change' : ''}} animation="{{cardItem.animationData}}" >
<view class="front card-item">{{cardItem.front}}</view>
<view class="back card-item">{{cardItem.back}}</view>
</view>
</repeat>
</view>
|
script
allMove () {
// 110 是卡牌寬度加邊距
this.methods.shuffle.call(this, 110)
let timer = setTimeout(() => {
clearTimeout(timer)
this.methods.shuffle.call(this, 0)
this.$apply()
}, 1000)
},
// 洗牌
shuffle (translateUnit) {
let curCardData = this.cardData
curCardData.map((item, index) => {
let animation = wepy.createAnimation({
duration: 500,
timingFunction: 'ease'
})
animation.export()
switch (index) {
case 0:
animation.translate(translateUnit, translateUnit).step()
break
case 1:
animation.translate(0, translateUnit).step()
break
case 2:
animation.translate(-translateUnit, translateUnit).step()
break
case 3:
animation.translate(translateUnit, 0).step()
break
case 4:
animation.translate(0, 0).step()
break
case 5:
animation.translate(-translateUnit, 0).step()
break
case 6:
animation.translate(translateUnit, -translateUnit).step()
break
case 7:
animation.translate(0, -translateUnit).step()
break
case 8:
animation.translate(-translateUnit, -translateUnit).step()
break
}
item.animationData = animation.export()
})
this.cardData = curCardData
this.$apply()
},
|
算法后面需要優(yōu)化,我們先完成功能效果, 效果如下

dom代碼
<view class="card-module">
<view class="card {{showClass ? 'change' : ''}} {{curIndex === index ? 'getprize' : ''}}" @tap="itemChage({{cardItem}}, {{index}})" animation="{{cardItem.animationData}}" >
<view class="front card-item">{{cardItem.front}}</view>
<view class="back card-item">{{cardItem.back}}</view>
</view>
</repeat>
</view>
|
script代碼
data中定義一個(gè)curIndex = -1的對(duì)象
data = {
curOpen: -1,
}
methods = {
// 抽獎(jiǎng)
itemChage (item, curIndex) {
this.cardData[curIndex].front = 'iphone x'
console.log(item, curIndex)
this.curOpen = curIndex
}
}
|
less
.card.getprize{
.front{
z-index:2;
transform: rotateY(0deg);
}
.back{
z-index:1;
transform: rotateY(180deg);
}
}
|
效果如下

現(xiàn)在我們就已經(jīng)完成了基本的需求;但是在位移動(dòng)畫時(shí)候代碼寫的太丑陋了。 我們來(lái)想想怎么優(yōu)化算法; 我們現(xiàn)在就九宮格布局,我們可以看成是二維布局

那我們是不是可以在卡牌中也使用二維數(shù)組布局屬性
resetData () {
const total = 9 // 總數(shù)
const lineTotal = 3 // 單行數(shù)
curCardData.map((item, index) => {
let curCardData = this.cardData
let x = index % lineTotal
let y = parseInt(index / lineTotal)
item.twoArry = {x, y}
})
}
|
在位移動(dòng)畫中使用二維布局的差值進(jìn)行位移
// 洗牌
shuffle (translateUnit) {
let curCardData = this.cardData
curCardData.map((item, index) => {
let animation = wepy.createAnimation({
duration: 500,
timingFunction: 'ease'
})
animation.export()
const translateUnitX = translateUnit * (1 - item.twoArry.x)
const translateUnitY = translateUnit * (1 - item.twoArry.y)
animation.translate(translateUnitX, translateUnitY).step()
item.animationData = animation.export()
})
this.cardData = curCardData
this.$apply()
},
|