你們對下面這個動畫效果想必都並不陌生了: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
只要再知道拋物線軌跡上任意一點座標便可,而小球所在的拋物線軌跡上,除了起始點座標外,還有一點座標確定是已知的,那就是拋物線末尾座標,即購物車元素的座標,到此,拋物線方程就搞定了。
小球拋物線動畫的關鍵就是這個拋物線軌跡方程,只要獲得了此方程公式,剩下的就很好解決了,關於拋物線方程更多詳細可見 張鑫旭
搞定了拋物線方程以後,接下來就是如何處理拋物小球的問題了。
每一次點擊增長按鈕,就會出現一個沿着拋物線軌跡拋向購物車的小球,每一個小球由於出現的座標以及時間不一樣,拋物線軌跡並不必定徹底重合,因此須要對這些小球進行單獨控制。
能夠將每一個拋物小球封裝成一個組件,每多處一個小球就至關因而在頁面上多增長了一個此組件,須要給組件傳入的關鍵 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 }
}
效果以下:
上述 react
實現的動畫,若是應用在實際項目中,有的時候可能會感受拋物線有點彆扭,咱們多是但願拋物線軌跡與小球拋出點的水平方向相切,即小球拋出點座標是拋物線的頂點,看起來會比較順滑,相似下面這種:
若是是這樣的話,那麼拋物線方程就要從新設定一下了。
因爲小球拋出點爲頂點,頂點已知,那麼可根據拋物線頂點式進行推導:
// 拋物線頂點式,(h,k)爲頂點座標
y=a(x-h)^2+k(a≠0)
設定小球起始點座標爲 (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
動畫,爲每一個動畫顯式聲明 appear
和afterAppear
這兩個鉤子函數,在 appear
函數中實現小球運動動畫,在 afterAppear
函數中清除小球。
效果以下:
動畫的主體部分大概就是這樣了,至於其餘的一些小動畫,例如小球掉入購物車時,購物車發生抖動等就很簡單了,很少說。
具體代碼放在 Github上了,有興趣能夠看一下,順便 star
哦~