在普通的網頁開發中,動畫效果可以通過css3來實現大部分需求,在小程式開發中同樣可以使用css3
,同時也可以通過api
方式來實現。
API解讀
小程式中,通過呼叫api
來建立動畫,需要先建立一個例項物件。這個物件通過wx.createAnimation
返回,animation
的一系列屬性都基於這個例項物件。
建立這個物件
let animation = wx.createAnimation({
duration: 2000,
delay: 0,
timingFunction: "linear",
});
複製程式碼
這個animation
就是通過wx.createAnimation
之後返回的例項。在建立過程中,可以給這個例項新增一些屬性,如以上程式碼所示,等同於css3
中animation:$name 2s linear
的寫法。
新增動效
例項建立完成之後,基於該例項,新增需要的動態效果,動態型別可以查閱文件得知,以最常見的移動,旋轉為例:
animation.translate($width, 0).rotate($deg);
複製程式碼
結束動畫
.step()
表示一組動畫的結束
animation.step();
複製程式碼
匯出動畫
動畫效果新增完成了,如何給想要的dom新增動效呢。這裡需要用到.export()
匯出動畫佇列,賦值給某個dom物件。
this.setData({ moveOne: animation.export() })
複製程式碼
<view animation="{{moveOne}}"></view>
複製程式碼
例子
以下將通過2組動畫,來對比一下css3
與api
實現方式的不同。
一、模組移動動畫
動畫效果:
下圖有兩組動畫,分別為api
方式(上)與css3
方式(下)完成的效果,點選move按鈕,動畫啟動。
程式碼實現
以下分別為css3
與api
的核心程式碼:
css3:
<!-- 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>
複製程式碼
// 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);
}
複製程式碼
// js
moveFunction(){
this.setData({
isMove: true
})
}
複製程式碼
css3
中通過動態改變class
類名來達到動畫的效果,如上程式碼通過one
、two
、three
、four
來分別控制移動的距離,通過sass可以避免程式碼過於冗餘的問題。(糾結如何在小程式中使用sass
的童鞋請看這裡哦:wechat-mina-template)
api:
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(); // 該事件觸發css3模組進行移動
},
// 模組移動方法
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] 代表需要繫結動畫的陣列物件
[ele]: animation.export()
})
}.bind(this), 2000)
}
moveFunc();
let interval = setInterval(moveFunc,4000)
}
複製程式碼
效果圖可見,模組之間都是簡單的移動,可以將他們的運動變化寫成一個公共的事件,通過向事件傳值,來移動到不同的位置。其中的引數w,h,m,ele
分別表示發散水平方向移動的距離、聚攏時垂直方向、水平方向的距離以及需要修改animationData
的物件。
通過這種方法產生的動畫,無法按照原有軌跡收回,所以在事件之後設定了定時器,定義在執行動畫2s之後,執行另一個動畫。同時動畫只能執行一次,如果需要迴圈的動效,要在外層包裹一個重複執行的定時器到。
檢視原始碼,發現api
方式是通過js
插入並改變內聯樣式來達到動畫效果,下面這張動圖可以清晰地看出樣式變化。
列印出賦值的animationData
,animates
中存放了動畫事件的型別及引數;options
中存放的是此次動畫的配置選項,transition
中存放的是wx.createAnimation
呼叫時的配置,transformOrigin
是預設配置,意為以物件的中心為起點開始執行動畫,也可在wx.createAnimation
時進行配置。
二、音樂播放動畫
上面的模組移動動畫不涉及邏輯互動,因此新嘗試了一個音樂播放動畫,該動畫需要實現暫停、繼續的效果。
動畫效果:
兩組不同的動畫效果對比,分別為api
(上)實現與css3
實現(下):
程式碼實現
以下分別是css3
實現與api
實現的核心程式碼:
css3:
<!-- 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>
複製程式碼
// scss
.musicRotate{
animation: rotate 3s linear infinite;
}
@keyframes rotate{
from{
transform: rotate(0deg)
}
to{
transform: rotate(359deg)
}
}
.musicPaused{
animation-play-state: paused;
}
複製程式碼
// js
playTwo(){
this.setData({
playTwo: !this.data.playTwo
},()=>{
let back = this.data.backgroundAudioManager;
if(this.data.playTwo){
back.play();
} else {
back.pause();
}
})
}
複製程式碼
通過playTwo
這個屬性來判斷是否暫停,並控制css
類的新增與刪除。當為false
時,新增.musicPaused
類,動畫暫停。
api:
<!-- 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>
複製程式碼
// js
play(){
this.setData({
play: !this.data.play
},()=>{
let back = this.data.backgroundAudioManager;
if (!this.data.play) {
back.pause();
// 跨事件清除定時器
clearInterval(this.data.rotateInterval);
} else {
back.play();
// 繼續旋轉,this.data.i記錄了旋轉的程度
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
);
// 全域性定時事件
this.setData({
rotateInterval: rotateInterval
})
}
複製程式碼
通過api
實現的方式是通過移除animationData
來控制動畫,同時暫停動畫也需要清除定時器,由於清除定時器需要跨事件進行操作,所以定了一個全域性方法rotateInterval
。
api
方式定義了旋轉的角度,但旋轉到該角度之後便會停止,如果需要實現重複旋轉效果,需要通過定時器來完成。因此定義了變數i,定時器每執行一次便加1,相當於每1s旋轉30°,對animation.rotate()
中的度數動態賦值。暫停之後繼續動畫,需要從原有角度繼續旋轉,因此變數i需要為全域性變數。
程式碼變化
下圖可以看出,api
方式旋轉是通過不斷累加角度來完成,而非css3
中迴圈執行。
對比
通過上述兩個小例子對比,無論是便捷度還是程式碼量,通過css3
來實現動畫效果相對來說是更好的選擇。api
方式存在較多侷限性:
- 動畫只能執行一次,迴圈效果需要通過定時器完成。
- 無法按照原有軌跡返回,需要返回必須定義定時器。
- 頻繁藉助定時器在效能上有硬傷。
綜合以上,推薦通過css3
來完成動畫效果。
廣而告之
本文釋出於薄荷前端週刊,歡迎Watch & Star ★,轉載請註明出處。