- 原文地址:A gentle introduction to React Motion
- 原文作者:Nash Vail
- 譯文出自:掘金翻譯計劃
- 本文永久連結:github.com/xitu/gold-m…
- 譯者:doctype233
- 校對者:
React 很棒,在過去的幾周裡,我用它玩得很開心,所以我決定嘗試一下React Motion。一開始 API 就讓我感到有困惑和棘手,但是最終一切開始變得有意義,不過這需要時間。遺憾的是,我在網上找不到合適的 React Motion 教程,所以我決定把這篇文章寫出來,不僅是作為一個開發者們的資源,也能給我自己作參考。
React Motion 對外暴露三個主要的元件:Motion, StaggeredMotion 和 TransitionMotion。在本教程中,我們將一起看一看 Motion 元件,之後你會發現將在這一部分花費大量時間。
由於這是一個 React Motion 教程,所以我將假設你有點熟悉 React 以及 ES2015。
我們將在使用 React Motion 重新建立 一個 Framerjs 的例子 時探索 API。你可以在這找到程式碼的最終版本 在這。
最終效果
我們首先要研究一點數學問題,但是不要擔心,我會盡可能詳細地解釋每一個步驟。你可以直接跳過這一部分到 React.start(); 部分。
準備好了嗎? 那就開始吧...
Math.start();
我們可以把藍色的大按鈕稱為——主按鈕, 從藍色按鈕上飛出的按鈕稱為——子按鈕。
Fig. 1
子按鈕擁有兩種位置狀態, 1) 子按鈕均隱藏在主按鈕後面的位置, 2) 子按鈕在主按鈕周圍排列成一個圓圈的位置。
這裡就出現了數學問題,我們必須想出一種方法,在一個完美的圓中均勻地排列主按鈕周圍的子按鈕。你可以通過試錯法將這些值通過程式碼寫死,但認真的說,誰會這麼做呢?另外,一旦你找到正確的數學方法,只要你願意你可以擺放任意多的子按鈕,而他們都會自動排列自己。
首先讓我們瞭解幾個術語。
M_X, M_Y
Fig. 2
M_X, M_Y 分別表示以主按鈕為中心的 X 和 Y 座標。(M_X, M_Y) 這個點將用作計算每個子按鈕的距離和方向的參考。
每個子按鈕最初都隱藏在主按鈕中心的後面,中心座標為 M_X, M_Y。
分離角、扇形角、飛出半徑
Fig. 3
飛出半徑為子按鈕飛出後距離主按鈕的距離,其他兩個詞語的釋義看起來不言自明。
還需要注意一個地方,
扇形角 = (子按鈕數-1) * 分離角
現在,我們需要設計一個函式,該函式接收子按鈕 (0, 1, 2, 3 …) 的索引,並返回子按鈕的新位置的 x 和 y 的座標。
基準角、索引
Fig. 4
由於通常來說三角學中的角度是從 x 軸的正方向測量的,我們將從相反的方向(右到左)開始給我們的子按鈕編號。這樣,以後我們就不必在每次需要子按鈕的最後位置時乘以負一。
當我們看到它時,請注意 (參見 Fig. 3)
基準角 = (180 — 扇形角)/2
(一定程度上)。
角
Fig. 5
每個子按鈕都有它自己的角度,我稱之為角。這個角是計運算元按鈕最終位置所需的最後一條資訊。
請注意, (參見 Fig. 3, Fig. 4)
索引為 i 的子按鈕的角度 = 基準角 + ( i * 分離角)
現在,一旦我們有了每個子按鈕的角,
Fig. 6
我們就能夠為每個子按鈕計算 增量X and 增量Y。
請注意 (參見 Fig. 2),
子按鈕的最終 X 軸座標 = M_X + 增量X
子按鈕的最終 Y 軸座標 = M_Y - 增量Y
(我們從 M_Y 中減去增量X,因為不同於原點在左下角的一般座標系,瀏覽器的原點在左上角,所以為了方便移動,你可以降低他們 y 軸座標的值。)
所以,這些就是我們所需要的數學方法,現在我們有兩樣東西:每個子按鈕的初始位置 (M_X, M_Y) 和子按鈕的最終位置,剩下的魔發就交由 React 來完成吧!
React.start();
在下面的關鍵程式碼中,你將會看到發生什麼,點選主按鈕,我們將 isOpen 的狀態變數設定為 true (第85行)。一旦 isOpen 為 true,就會傳遞不同的子按鈕的樣式(第97行,第66行,第75行)。
結果:
Fig. 7
好的,我們在此處完成了很多操作,我們在按鈕上設定子按鈕的初始位置和最終位置,現在我們需要做的就是新增 React Motion 來啟用在初始位置和最終位置之間的動畫。
React-Motion.start();
獲取 幾個引數 每個引數是可選的,但我們不關心這裡的可選引數,因為我們沒有做任何與這個引數有關的事情。
其中 一個引數是 style, style 將作為引數傳遞到回撥函式中,該函式包含內建的 interpolated values ,然後執行它的動畫。
(第8行 : 因為正在React中執行迭代,所以需要將一個 key 引數傳遞給子元件。)
就像這樣,
即使在這樣做以後,結果也不會與圖 Fig. 7 有所不同,為什麼這麼說?好吧,我們還需要最後一步,使用_spring_。
正如前面提到的, 回撥函式包含內建的值,也就是說, spring 幫助函式內建的值插入樣式值。
我們需要修改 initialChildButtonStyles 和 finalChildButtonStyles 並注意 top 和 left 被 spring 覆蓋的值。這些是僅有的改變,現在,
Fig. 8
spring 可選地接收第二個引數,這是一個包含兩個數字的陣列 [Stiffness, damping],預設值為[170,26],這導致了上圖 Fig. 8 中呈現的結果。
將 Stiffness 視為動畫發生的速度,這不是一個非常精確的假設,只是速度越大的值越大。Dampness 是一個晃動效果引數,不過相反的,值越小,晃動效果越明顯。
可以看看這個
[320, 8] — Fig. 9
[320, 17] — Fig. 10
我們離最終完成很近了,但是還沒有。如果我們在每次下一個子按鈕開始動畫前新增延遲會怎樣?為了達到最終效果,這正是我們需要做的,但這樣做並不那麼簡單,我不得不把每個運動元件以陣列的形式儲存到狀態變數中,然後一個一個地為每個子按鈕改變狀態以達到期望的效果,程式碼就像這樣
this.state = {
isOpen: false,
childButtons: []
};
複製程式碼
然後在 componentDidMount 方法中新增 childButtons
componentDidMount() {
let childButtons = [];
range(NUM_CHILDREN).forEach(index => {
childButtons.push(this.renderChildButton(index));
});
this.setState({childButtons: childButtons.slice(0)});
}
複製程式碼
最終開啟選單功能得以實現:
我們在這裡做了一些美學的調整,如新增圖示和一些旋轉效果,我們得到最終效果如下。
方法已覆蓋,你可以設定任何數量的子按鈕
NUM_CHILDREN = 1
NUM_CHILDREN = 3
NUM_CHILDREN = 8
相當酷對嗎? 再說一遍,你可以 在這找到相應程式碼。如果你覺得這篇文章有幫助,請點選下面的推薦按鈕。
如果有一些問題、評論、建議或僅僅是想聊個天?可以在 Twitter 上找到我 @NashVail 或者給我發電子郵件 hello@nashvail.me。
你可能還會喜歡
如果發現譯文存在錯誤或其他需要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可獲得相應獎勵積分。文章開頭的 本文永久連結 即為本文在 GitHub 上的 MarkDown 連結。
掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 Android、iOS、前端、後端、區塊鏈、產品、設計、人工智慧等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃、官方微博、知乎專欄。