如何作活動頁面的滾動動畫?讓用戶體驗MAX的demo在這裏!

本文由雲+社區發表css

最近的一個活動頁面須要作一個能夠左右滑動的抽籤效果,故經過用css的transform屬性和js結合來模擬能夠無限滾動的效果。html

先上效果:git

img

demo地址:https://kiroroyoyo.github.io/cardTransform/index.htmlgithub

實現過程

1. 結構與樣式

結構:卡片分先後兩排,每列插入10個div結點,以便作左右位移效果。chrome

樣式:設置每一列都剛好好在中間位置(或中間位置附近),以下所示。dom

a. 前排(cardFrond)相對於視口的初始位置(left:-255.5%;):佈局

img

b. 後排(backFrond)相對於視口的初始位置(left:-228.3%;):動畫

img

2. 無限滾動原理

因爲這裏的中止位置是固定的,前排永遠是當前卡片相對於視口居中,後排永遠是兩個卡片相對於視口居中,且每一個卡片是同樣的,因此當卡片列表向前或向右移動到一個目標位置時,都將列表重置爲初始位置繼續滾動。以下圖之前排卡片爲例:this

img

因此當滾動中止後會統一將列表樣式設置爲transform: translateX(0)。而對於用戶這一操做是無感知的,認爲已經滑動到了新的位置。調試

3.滑動過程實現

a. 目標位移與幀位移

爲了作出滑動後到停留位置的緩動效果,因此當用戶左右滑動屏幕時,會記錄滑動距離,計算出卡片該到的目標位移位置,目標位移位置是有規則的,由於這裏有10張卡片均分寬度,位置必須是(100%/10)的整數倍,例如-40%、-30%、……40%,這樣才能保證目標位置與初始位置相重合。

目標位移代碼片斷

onDocumentMouseUp : function(e){
    //若是是點擊事件 不設置移動
    if (!this.fingerTouch)
      return;
    this.moveDirect = this.lon > 0 ? 1 : -1;
    this.transNum = this.lon/10 + this.moveDirect;
    this.lon = Math.round(this.transNum) * 10;
    this.fingerTouch = false;   
}

記錄了目標位移後,每一幀會以必定的幀位移不斷靠近目標位移,使其在手指離開屏幕時仍有慢慢滑動到目標位置的緩動效果。此時須要判斷當前位置是否大於40%或者小於-40%,若超過這個極限值須要重設目標位移及幀位移,使其在極限值內。

animate: function(){
    this.prePos += (this.lon - this.prePos) * 0.1;
    if (this.prePos > 40) {
      this.lon = this.lon - 40;
      this.prePos = this.prePos - 40;
    }else if (this.prePos < -40) {
      this.lon = this.lon + 40;
      this.prePos = this.prePos + 40;
    }
    //判斷是否到達了目標位置
    if (Math.abs(this.prePos - this.lon) < 0.01 && Math.abs(this.lon) > 0.01 && (!this.fingerTouch))
    {
        this.ani_move = false;
        this.prePos = 0;
        this.frondCard.style = "transform: translateX("+ this.prePos +"%)";
        this.backCard.style = "transform: translateX("+ this.prePos +"%)";
    }else{
        this.frondCard.style = "transform: translateX("+ this.prePos +"%)";
        this.backCard.style = "transform: translateX("+ (-this.prePos) +"%)";
        requestAnimationFrame(this.animate.bind(this));
    }
  },

b. 連續滑動判斷

當在上次滑動動畫還未播放結束時用戶又進行了第二次滑動時,須要執行一下操做:

​ 1). 判斷滑動時機處於上次滑動手指已離開屏幕但動畫還未結束,此時須要記錄兩個flag,一個是ani_move,記錄動畫是否仍在進行,fingerTouch記錄手指是否停留屏幕。

​ 2). 判斷第二次滑動是否與第一次不一樣方向,若不一樣向需重置上次幀位移爲0。以避免上次幀位移太大影響移動方向。

1)與2)代碼片斷:

if( this.ani_move && this.fingerTouch == false) {
    // 判斷是否不一樣向
    if (((e.clientX - prex) > 0 ? 1: -1) == -this.moveDirect ) {
        this.lon = 0;
        this.prePos = 0;
        this.moveDirect = -this.moveDirect;
    }
}

3). 取消第二次滑動時的動畫播放和位移重置

// 如果上次動畫未結束不須要再次啓動動畫和重置目標位移
if( this.ani_move && this.fingerTouch == false) {
}
else {
    this.lon = 0;
     cardAnimate.animate();
}

寫在最後

目前這個滑動效果只能針對卡片相同,停留位置固定的狀況,由於須要作到位置重合。使用css transform來作無限滾動的效果,能夠避免改變dom結點帶來的頁面從新佈局。

下圖是chrome cpu6倍減速調試效果,沒有觸發layout,FPS基本維持在60左右。

img

代碼地址:

https://github.com/kiroroyoyo/cardTransform

此文已由做者受權騰訊雲+社區發佈

相關文章
相關標籤/搜索