React、Vue實現購物車小球拋物線效果

你們對下面這個動畫效果想必都並不陌生了:javascript

這裏寫圖片描述

點擊增長商品的按鈕,會有一個小球作拋物線掉入購物車中,對這個動畫一直很感興趣,因此稍稍探究了一下vue


拋物線軌跡方程

實現此動畫效果的難點在於,如何控制拋物小球在每一幀的座標,由於只要控制好小球的每幀座標,則小球的運動軌跡也就肯定了。java

通常狀況下,這種拋物小球的運動軌跡都是拋物線,或者近似拋物線(例如本文開頭的那個餓了麼圖片,小球運動感受並非真正的拋物線運動),道理其實都是同樣的,這裏先設定小球就是拋物線運動。react

這裏寫圖片描述

拋物線的通常方程爲:git

y=ax^2+bx+cgithub

其中, x y爲座標,因此此方程中只要肯定 a b c這 3個參數的值,就能獲得一條拋物線軌跡方程式。web

3個參數須要 3個條件才能徹底求解,也就是說只要知道拋物線軌跡上隨意 3個點的座標便可。數組

不過,由於這裏的座標軸是咱們本身虛構的,咱們是在解決實際問題,而不是解決數學問題,因此不須要太複雜,怎麼簡單怎麼來,若是假定拋物線軌跡的起始點座標爲 (0,0),那麼根據上述拋物線方程能夠獲得 c=0,拋物線方程就變成了:app

y=ax^2+bxsvg

另外, 參數 a其實是一個可控的常量,經過設定 a的值來肯定拋物線在每一點處的曲率,因此 a能夠看作是已知的

因此,只須要求出 b便可:

b=(y+ ax^2) / x

只要再知道拋物線軌跡上任意一點座標便可,而小球所在的拋物線軌跡上,除了起始點座標外,還有一點座標確定是已知的,那就是拋物線末尾座標,即購物車元素的座標,到此,拋物線方程就搞定了。

小球拋物線動畫的關鍵就是這個拋物線軌跡方程,只要獲得了此方程公式,剩下的就很好解決了,關於拋物線方程更多詳細可見 張鑫旭


在 React中實現拋物小球動畫

搞定了拋物線方程以後,接下來就是如何處理拋物小球的問題了。

每一次點擊增長按鈕,就會出現一個沿着拋物線軌跡拋向購物車的小球,每一個小球由於出現的座標以及時間不一樣,拋物線軌跡並不必定徹底重合,因此須要對這些小球進行單獨控制。

能夠將每一個拋物小球封裝成一個組件,每多處一個小球就至關因而在頁面上多增長了一個此組件,須要給組件傳入的關鍵 props數據有以下幾個。

  • 小球的起始座標
    根據上述關於拋物線方程的推導可知,想要肯定此方程,須要小球的起始座標以及末尾座標,設定其實座標以下表示:
// 起始點座標
position = {x0, y0}
// 末尾點座標
target = {x1, y1}
  • 曲率 curvature
    在上述推導的拋物線方程中,參數a是可控的,由咱們本身來定,經過這個參數控制拋物線在各點的曲率

  • 速度 speed
    小球的運動速度也是能夠控制的,經過此參數來控制小球的運動速度

  • 清除函數以及小球id
    小球在進入到購物車後會自動消失,因此這裏須要處理一下,頁面中可能同時存在不少個小球,根據 id來肯定到底哪一個小球須要清除掉。

根據以上推斷,小球組件能夠是下面這個樣子:

<Ball  position={position} target={target} id={id} curvature={curvature} speed={speed} changeFlyBallCount={changeFlyBallCount}/>

設定一個 state做爲頁面上的小球組件數據來源:

balls: []

balls數組中的每一項表明着一個須要顯示的小球,當須要在頁面上顯示小球時,則向 balls中追加一個小球數據項,此項中包含小球的起始點座標以及 一個獨一無二的小球id(可使用時間戳代替),以下:

balls: [
    {
  
  
  

 id, position: {x, y}}
]

當小球進入到購物車中須要被清除掉時,只須要根據 id查找出小球的數據項,而後將此項從 balls中刪掉便可,以下:

for (let i=0; i<balls.length; i++) { if(balls[i].id === id) { // 清除小球 balls.splice(i, 1) break }
}

效果以下:

這裏寫圖片描述


在 Vue中實現拋物小球動畫

上述 react實現的動畫,若是應用在實際項目中,有的時候可能會感受拋物線有點彆扭,咱們多是但願拋物線軌跡與小球拋出點的水平方向相切,即小球拋出點座標是拋物線的頂點,看起來會比較順滑,相似下面這種:

這裏寫圖片描述

若是是這樣的話,那麼拋物線方程就要從新設定一下了。

因爲小球拋出點爲頂點,頂點已知,那麼可根據拋物線頂點式進行推導:

// 拋物線頂點式,(h,k)爲頂點座標
y=a(x-h)^2+k(a0)

設定小球起始點座標爲 (0, 0),則只須要再已知一點座標,獲得參數 a便可,而這一點座標顯而易見能夠是 拋物線末尾點座標(x1,y1)上式中的參數 a爲:

a = y1/(x1^2)

拋物線方程搞定。

這裏可使用 Vue動畫鉤子函數來完成小球拋物動畫,其他的與上述 react大致相同,設定一個數組數據源 balls,當須要顯示小球時,就向裏面追加一個數據項,有一點須要注意,因爲Vue動畫自己的邏輯,當須要清除小球的時候,就不能像上面 react實現的那樣直接將對應的數據項從 balls數組裏面刪除了,能夠多設定一個標誌變量 show,當須要顯示的時候,將 show設爲 true,當須要小球消失時,將對應的小球數據項的 show設爲 false,以下:

// x,y爲小球起始點座標
balls: [
  {
  
  
  

 id, show, x, y}
]

每一個小球都看做是一個 transiton動畫,爲每一個動畫顯式聲明 appearafterAppear這兩個鉤子函數,在 appear函數中實現小球運動動畫,在 afterAppear函數中清除小球。

效果以下:

這裏寫圖片描述


動畫的主體部分大概就是這樣了,至於其餘的一些小動畫,例如小球掉入購物車時,購物車發生抖動等就很簡單了,很少說。
具體代碼放在 Github上了,有興趣能夠看一下,順便 star哦~