在普通的網(wǎng)頁(yè)開發(fā)中,動(dòng)畫效果可以通過css3來實(shí)現(xiàn)大部分需求,在小程序開發(fā)中同樣可以使用 css3 ,同時(shí)也可以通過 api 方式來實(shí)現(xiàn)。
指路: 小程序animatiom動(dòng)畫API
小程序中,通過調(diào)用 api 來創(chuàng)建動(dòng)畫,需要先創(chuàng)建一個(gè)實(shí)例對(duì)象。這個(gè)對(duì)象通過 wx.createAnimation 返回, animation 的一系列屬性都基于這個(gè)實(shí)例對(duì)象。
let animation = wx.createAnimation({
duration: 2000,
delay: 0,
timingFunction: "linear",
});
復(fù)制代碼
這個(gè) animation 就是通過 wx.createAnimation 之后返回的實(shí)例。在創(chuàng)建過程中,可以給這個(gè)實(shí)例添加一些屬性,如以上代碼所示,等同于 css3 中 animation:$name 2s linear 的寫法。
實(shí)例創(chuàng)建完成之后,基于該實(shí)例,添加需要的動(dòng)態(tài)效果,動(dòng)態(tài)類型可以查閱文檔得知,以最常見的移動(dòng),旋轉(zhuǎn)為例:
animation.translate($width, 0).rotate($deg); 復(fù)制代碼
.step() 表示一組動(dòng)畫的結(jié)束
animation.step(); 復(fù)制代碼
動(dòng)畫效果添加完成了,如何給想要的dom添加動(dòng)效呢。這里需要用到 .export() 導(dǎo)出動(dòng)畫隊(duì)列,賦值給某個(gè)dom對(duì)象。
this.setData({ moveOne: animation.export() })
復(fù)制代碼
<view animation="{{moveOne}}"></view>
復(fù)制代碼
以下將通過2組動(dòng)畫,來對(duì)比一下 css3 與 api 實(shí)現(xiàn)方式的不同。
下圖有兩組動(dòng)畫,分別為 api 方式(上)與 css3 方式(下)完成的效果,點(diǎn)擊move按鈕,動(dòng)畫啟動(dòng)。

以下分別為 css3 與 api 的核心代碼:
<!-- wxml -->
<view class='border'>
<view class='css-block {{isMove && "one"}}'></view>
<view class='css-block {{isMove && "two"}}'></view>
<view class='css-block {{isMove && "three"}}'></view>
<view class='css-block {{isMove && "four"}}'></view>
</view>
復(fù)制代碼
// scss
@mixin movePublic($oldLeft,$oldTop,$left,$top) {
from {
transform:translate($oldLeft,$oldTop);
}
to {
transform:translate($left,$top);
}
}
@mixin blockStyle($color,$name) {
background: $color;
animation:$name 2s linear infinite alternate;
}
.one {
@include blockStyle(lightsalmon,onemove);
}
@keyframes onemove {
@include movePublic(50rpx,-25rpx,-150rpx,0rpx);
}
.two {
@include blockStyle(lightblue,twomove);
}
@keyframes twomove {
@include movePublic(0rpx,25rpx,-50rpx,0rpx);
}
.three {
@include blockStyle(lightgray,threemove);
}
@keyframes threemove {
@include movePublic(0rpx,25rpx,50rpx,0rpx);
}
.four {
@include blockStyle(grey,fourmove);
}
@keyframes fourmove {
@include movePublic(-50rpx,-25rpx,150rpx,0rpx);
}
復(fù)制代碼
// js
moveFunction(){
this.setData({
isMove: true
})
}
復(fù)制代碼
css3 中通過動(dòng)態(tài)改變 class 類名來達(dá)到動(dòng)畫的效果,如上代碼通過 one 、 two 、 three 、 four 來分別控制移動(dòng)的距離,通過sass可以避免代碼過于冗余的問題。 (糾結(jié)如何在小程序中使用 sass 的童鞋請(qǐng)看這里哦: wechat-mina-template )
moveClick(){
this.move(-75,-12.5,25,'moveOne');
this.move(-25,12.5, 0,'moveTwo');
this.move(25, 12.5,0,'moveThree');
this.move(75, -12.5,-25,'moveFour');
this.moveFunction(); // 該事件觸發(fā)css3模塊進(jìn)行移動(dòng)
},
// 模塊移動(dòng)方法
move: function (w,h,m,ele) {
let self = this;
let moveFunc = function () {
let animation = wx.createAnimation({
duration: 2000,
delay: 0,
timingFunction: "linear",
});
animation.translate(w, 0).step()
self.setData({ [ele]: animation.export() })
let timeout = setTimeout(function () {
animation.translate(m, h).step();
self.setData({
// [ele] 代表需要綁定動(dòng)畫的數(shù)組對(duì)象
[ele]: animation.export()
})
}.bind(this), 2000)
}
moveFunc();
let interval = setInterval(moveFunc,4000)
}
復(fù)制代碼
效果圖可見,模塊之間都是簡(jiǎn)單的移動(dòng),可以將他們的運(yùn)動(dòng)變化寫成一個(gè)公共的事件,通過向事件傳值,來移動(dòng)到不同的位置。其中的參數(shù) w,h,m,ele 分別表示發(fā)散水平方向移動(dòng)的距離、聚攏時(shí)垂直方向、水平方向的距離以及需要修改 animationData 的對(duì)象。
通過這種方法產(chǎn)生的動(dòng)畫,無法按照原有軌跡收回,所以在事件之后設(shè)置了定時(shí)器,定義在執(zhí)行動(dòng)畫2s之后,執(zhí)行另一個(gè)動(dòng)畫。同時(shí) 動(dòng)畫只能執(zhí)行一次 ,如果需要循環(huán)的動(dòng)效,要在外層包裹一個(gè)重復(fù)執(zhí)行的定時(shí)器到。
查看源碼,發(fā)現(xiàn) api 方式是通過 js 插入并改變內(nèi)聯(lián)樣式來達(dá)到動(dòng)畫效果,下面這張動(dòng)圖可以清晰地看出樣式變化。

打印出賦值的 animationData , animates 中存放了動(dòng)畫事件的類型及參數(shù); options 中存放的是此次動(dòng)畫的配置選項(xiàng), transition 中存放的是 wx.createAnimation 調(diào)用時(shí)的配置, transformOrigin 是默認(rèn)配置,意為以對(duì)象的中心為起點(diǎn)開始執(zhí)行動(dòng)畫,也可在 wx.createAnimation時(shí)進(jìn)行配置。

上面的模塊移動(dòng)動(dòng)畫不涉及邏輯交互,因此新嘗試了一個(gè)音樂播放動(dòng)畫,該動(dòng)畫需要實(shí)現(xiàn)暫停、繼續(xù)的效果。

兩組不同的動(dòng)畫效果對(duì)比,分別為 api (上)實(shí)現(xiàn)與 css3 實(shí)現(xiàn)(下):

以下分別是 css3 實(shí)現(xiàn)與 api 實(shí)現(xiàn)的核心代碼:
<!-- wxml -->
<view class='music musicTwo musicRotate {{playTwo ? " ": "musicPaused"}} ' bindtap='playTwo'>
<text class="iconfont has-music" wx:if="{{playTwo}}"></text>
<text class="iconfont no-music" wx:if="{{!playTwo}}"></text>
</view>
復(fù)制代碼
// scss
.musicRotate{
animation: rotate 3s linear infinite;
}
@keyframes rotate{
from{
transform: rotate(0deg)
}
to{
transform: rotate(359deg)
}
}
.musicPaused{
animation-play-state: paused;
}
復(fù)制代碼
// js
playTwo(){
this.setData({
playTwo: !this.data.playTwo
},()=>{
let back = this.data.backgroundAudioManager;
if(this.data.playTwo){
back.play();
} else {
back.pause();
}
})
}
復(fù)制代碼
通過 playTwo 這個(gè)屬性來判斷是否暫停,并控制 css 類的添加與刪除。當(dāng)為 false 時(shí),添加 .musicPaused 類,動(dòng)畫暫停。
<!-- wxml -->
<view class='music' bindtap='play' animation="{{play && musicRotate}}">
<text class="iconfont has-music" wx:if="{{play}}"></text>
<text class="iconfont no-music" wx:if="{{!play}}"></text>
</view>
復(fù)制代碼
// js
play(){
this.setData({
play: !this.data.play
},()=>{
let back = this.data.backgroundAudioManager;
if (!this.data.play) {
back.pause();
// 跨事件清除定時(shí)器
clearInterval(this.data.rotateInterval);
} else {
back.play();
// 繼續(xù)旋轉(zhuǎn),this.data.i記錄了旋轉(zhuǎn)的程度
this.musicRotate(this.data.i);
}
})
},
musicRotate(i){
let self = this;
let rotateFuc = function(){
i++;
self.setData({
i:i++
});
let animation = wx.createAnimation({
duration: 1000,
delay: 0,
timingFunction: "linear",
});
animation.rotate(30*(i++)).step()
self.setData({ musicRotate: animation.export() });
}
rotateFuc();
let rotateInterval = setInterval(
rotateFuc,1000
);
// 全局定時(shí)事件
this.setData({
rotateInterval: rotateInterval
})
}
復(fù)制代碼
通過 api 實(shí)現(xiàn)的方式是通過移除 animationData 來控制動(dòng)畫,同時(shí)暫停動(dòng)畫也需要清除定時(shí)器,由于清除定時(shí)器需要跨事件進(jìn)行操作,所以定了一個(gè)全局方法 rotateInterval 。
api 方式定義了旋轉(zhuǎn)的角度,但旋轉(zhuǎn)到該角度之后便會(huì)停止,如果需要實(shí)現(xiàn)重復(fù)旋轉(zhuǎn)效果,需要通過定時(shí)器來完成。因此定義了變量i,定時(shí)器每執(zhí)行一次便加1,相當(dāng)于每1s旋轉(zhuǎn)30°,對(duì) animation.rotate() 中的度數(shù)動(dòng)態(tài)賦值。暫停之后繼續(xù)動(dòng)畫,需要從原有角度繼續(xù)旋轉(zhuǎn),因此變量i需要為全局變量。
下圖可以看出, api 方式旋轉(zhuǎn)是通過不斷累加角度來完成,而非 css3 中循環(huán)執(zhí)行。

通過上述兩個(gè)小例子對(duì)比,無論是便捷度還是代碼量,通過 css3 來實(shí)現(xiàn)動(dòng)畫效果相對(duì)來說是更好的選擇。 api 方式存在較多局限性:
綜合以上,推薦通過 css3 來完成動(dòng)畫效果。