兩種方案開發小程序動畫

在普通的網頁開發中,動畫效果能夠經過css3來實現大部分需求,在小程序開發中一樣可使用css3,同時也能夠經過api方式來實現。javascript

指路:小程序animatiom動畫APIcss

API解讀

小程序中,經過調用api來建立動畫,須要先建立一個實例對象。這個對象經過wx.createAnimation返回,animation的一系列屬性都基於這個實例對象。html

建立這個對象

let animation = wx.createAnimation({
        duration: 2000,
        delay: 0,
        timingFunction: "linear",
    });
複製代碼

這個animation就是經過wx.createAnimation以後返回的實例。在建立過程當中,能夠給這個實例添加一些屬性,如以上代碼所示,等同於css3animation:$name 2s linear的寫法。前端

添加動效

實例建立完成以後,基於該實例,添加須要的動態效果,動態類型能夠查閱文檔得知,以最多見的移動,旋轉爲例:java

animation.translate($width, 0).rotate($deg);
複製代碼

結束動畫

.step()表示一組動畫的結束webpack

animation.step();
複製代碼

導出動畫

動畫效果添加完成了,如何給想要的dom添加動效呢。這裏須要用到.export()導出動畫隊列,賦值給某個dom對象。css3

this.setData({ moveOne: animation.export() })
複製代碼
<view animation="{{moveOne}}"></view>
複製代碼

例子

如下將經過2組動畫,來對比一下css3api實現方式的不一樣。git

1、模塊移動動畫

動畫效果:

下圖有兩組動畫,分別爲api方式(上)與css3方式(下)完成的效果,點擊move按鈕,動畫啓動。github

image

代碼實現

如下分別爲css3api的核心代碼:web

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類名來達到動畫的效果,如上代碼經過onetwothreefour來分別控制移動的距離,經過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插入並改變內聯樣式來達到動畫效果,下面這張動圖能夠清晰地看出樣式變化。

代碼變化

打印出賦值的animationDataanimates中存放了動畫事件的類型及參數;options中存放的是這次動畫的配置選項,transition中存放的是wx.createAnimation調用時的配置,transformOrigin是默認配置,意爲以對象的中心爲起點開始執行動畫,也可在wx.createAnimation時進行配置。

animationData

2、音樂播放動畫

上面的模塊移動動畫不涉及邏輯交互,所以新嘗試了一個音樂播放動畫,該動畫須要實現暫停、繼續的效果。

動畫效果:

播放音樂

兩組不一樣的動畫效果對比,分別爲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方式存在較多侷限性:

  1. 動畫只能執行一次,循環效果須要經過定時器完成。
  2. 沒法按照原有軌跡返回,須要返回必須定義定時器。
  3. 頻繁藉助定時器在性能上有硬傷。

綜合以上,推薦經過css3來完成動畫效果。

廣而告之

本文發佈於薄荷前端週刊,歡迎Watch & Star ★,轉載請註明出處。

歡迎討論,點個贊再走吧 。◕‿◕。 ~

相關文章
相關標籤/搜索