DUICUO

HarmonyOSサードパーティオープンソースコンポーネント - Hongmeng JSはシミュレートされたAnt Forestを実装します

[[415355]]

詳細については、以下をご覧ください。

51CTOとHuaweiが共同で構築したHarmonyOSテクノロジーコミュニティ。

https://harmonyos..com

最終結果:

実装プロセスの分析:

1. 外部からコンポーネントに渡される配列(ボールのエネルギーのリスト)と、エネルギー収集アニメーションが終了する位置を受け取ります。

  1. <! -- waterFlake.js -->  
  2. 小道具: {
  3. // バックエンドから返されたボール情報
  4. ボールリスト: {
  5. デフォルト: [10, 11, 12, 13, 14],
  6. },
  7. // エネルギー収集アニメーション終了時のX座標
  8. コリジョン宛先X: {
  9. デフォルト: 350
  10. },
  11. // エネルギー収集アニメーション終了時のY座標
  12. 照合先Y: {
  13. デフォルト: 400
  14. }
  15. },

2. ボールの数に基づいて、各ボールのランダムな位置座標を生成します。

  1. // ボールのx座標配列を生成する
  2. xRandom = this.randomCommon(1, 8, this.ballList.length) とします。
  3. all_x = xRandom.map(item => {
  4. アイテム * 幅 * 0.10を返す
  5. });
  6. // ボールのy座標配列を生成する
  7. yRandom = this.randomCommon(1, 8, this.ballList.length); とします。
  8. all_y = yRandom.map(item => {
  9. 返されるアイテム * 高さ * 0.08
  10. })
  1. /**
  2. * 指定された範囲から N 個の一意の番号をランダムに選択します。
  3. * 最もシンプルで基本的な方法
  4. *
  5. * @param min範囲内の最小値を指定します
  6. * @param max指定された範囲内の最大値を指定します。
  7. * @param n 乱数の数
  8. * @乱数のリストを返す
  9. /
  10. ランダムコモン(最小,最大,n){
  11. もし (n > (最大値-最小値+ 1) ||最大値<最小値) {
  12. 戻る ヌル;
  13. }
  14. 結果を [] とします。
  15. count = 0 とします。
  16. while ( count < n) {
  17. let num = parseInt((Math.random() * ( max - min )) + min );
  18. フラグをtrueにします
  19. (j = 0; j < n; j++)の場合
  20. if (num == result[j]) {
  21. フラグ = false ;
  22. 壊す
  23. }
  24. }
  25. if (フラグ) {
  26. 結果[ count ] = num;
  27. カウント++;
  28. }
  29. }
  30. 結果を返します
  31. },

3. 入力エネルギー リストと生成されたボールの座標に基づいて、必要なボール データ リストを ballDataList[] に組み立てます。

  1. /**
  2. ballDataList 内の各オブジェクトには、次のプロパティが含まれます。
  3. * コンテンツ(ボールに表示されるテキスト情報)
  4. * x(水平座標)
  5. * y(垂直軸)
  6. /
  7. ボールデータリスト: [],
  1. データリストを [] とします
  2. for (let index = 0; index < this.ballList.length; index ++) {
  3. データリスト.push({
  4. コンテンツ: this.ballList[インデックス] + 'g'
  5. x: all_x[インデックス],
  6. y: all_y[インデックス]
  7. })
  8. }
  9. this.ballDataList = dataList; // ビューの更新をトリガーする

4. 小さなボールをランダムに表示するためのインターフェースを描画します。

  1. <! -- waterFlake.hml -->  
  2. <div class= "main_contain" ref= "main_contain" id= "main_contain" >
  3. <text for = "{{ ballDataList }}"  
  4. スタイル=": {{ $item.y }} px;
  5. : {{ $item.x }} ピクセル;
  6. >{{ $item.content } } テキスト>
  7.  
  8. </div>
  1. .main_contain {
  2. 幅: 100%;
  3. 位置:相対;
  4. }
  5.  
  6. 。ボール {
  7. 幅: 120px;
  8. 高さ: 120px;
  9. 背景色: #c3f593;
  10. 背景サイズ:100%;
  11. 境界線の半径: 60px;
  12. 境界線: #69c78e;
  13. ボーダーボトムスタイル: solid;
  14. 境界線の幅: 1px;
  15. 位置:絶対;
  16. テキスト配置: 中央;
  17. }

5. ボールにアニメーションを追加します。

HarmonyOS JSUI フレームワークの @keyframes アニメーションでは、初期アニメーション スタイル (from プロパティ) と終了スタイル (to プロパティ) のみを指定できるため、ボールのアニメーションを指定するには JS を使用するしかありません。

ボールが単純な上下運動をするアニメーションは、次の 2 つの方法で実装できます。

方法 1: 各ボールのアニメーションを無限回設定します。

  1. createShakeAnimate(el) {
  2. if (el == null || el == 未定義) {
  3. 戻る 
  4. }
  5. var オプション = {
  6. 期間: 2000年、
  7. 緩和: 「摩擦」
  8. 塗りつぶし: '前方'
  9. 反復回数: 「無限」
  10. };
  11. var フレーム = [
  12. {
  13. 変身: {
  14. 翻訳: '0px 0px'  
  15. },
  16. offset: 0.0 // アニメーション開始時
  17. },
  18. {
  19. 変身: {
  20. 翻訳: '0px 20px'  
  21. },
  22. offset: 0.5 // アニメーションが半分終わったとき。
  23. },
  24. {
  25. 変身: {
  26. 翻訳: '0px 0px'  
  27. },
  28. offset: 1.0 // アニメーションが終了したとき
  29. },
  30.  
  31. ];
  32. アニメーションを el.animate(フレーム、オプション) とします。
  33. リターンアニメーション
  34. },

方法 2: 各ボールを一方向のアニメーションに設定し、それを 1 回だけ実行し、アニメーションが終了したら reverse() メソッドを呼び出してアニメーションを反転します。

  1. createShakeAnimate(el) {
  2. if (el == null || el == 未定義) {
  3. 戻る 
  4. }
  5. var オプション = {
  6. 期間: 2000年、
  7. 緩和: 「摩擦」
  8. 塗りつぶし: '前方'
  9. 反復回数: 1,
  10. };
  11. var フレーム = [
  12. {
  13. 変身: {
  14. 翻訳: '0px 0px'  
  15. },
  16. オフセット: 0.0
  17. },
  18. {
  19. 変身: {
  20. 翻訳: '0px 20px'  
  21. },
  22. オフセット: 1.0
  23. },
  24. ];
  25. アニメーションを el.animate(フレーム、オプション) とします。
  26. アニメーション.onfinish =関数() {
  27. アニメーション.逆()
  28. };
  29. リターンアニメーション

フローティングアニメーションを実行する

  1. <! -- waterFlake.hml は各ボールに ID を割り当てます -->  
  2. <text for = "{{ ballDataList }}"  
  3. クラス= "ボール"  
  4. id= "ボール{{ $idx }}"  
  5. onclick = "onBallClick($idx,$item)"  
  6. スタイル=": {{ $item.y }} px;
  7. : {{ $item.x }} ピクセル;
  8. >{{ $item.content } } テキスト>
  1. <! -- waterFlake.js がアニメーションを実行します -->  
  2. プレイシェイクアニメーション() {
  3. setTimeout(() => {
  4. console.info( 'xwg playShakeAnimate ' );
  5. for (var index = 0; index < this.ballDataList.length; index ++) {
  6. el = this.$element(`ball${ index }`)とします。
  7. animate = this.createShakeAnimate(el) とします。
  8. アニメーション再生()
  9. }
  10. }, 50)
  11. },

6. ボールのクリック イベントとエネルギー収集アニメーションを設定します。

  1. onBallClick(インデックス, アイテム ) {
  2. // イベントを親コンポーネントに送信し、ボール情報をパラメーターとして渡します。
  3. this.$emit( ​​'ballClick' , item);
  4.  
  5. el = this.$element(`ball${ index }`)とします。
  6. this.playCollectionAnimate(el,インデックス)
  7. },
  1. /**
  2. * 収集したアニメーションを実行する
  3. * @param el
  4. * @paramインデックス 
  5. * @戻る 
  6. /
  7. playCollectionAnimate(el,インデックス) {
  8. if (this.isCollect) { // コレクションアニメーションが進行中の場合は、すぐに戻ります 
  9. 戻る 
  10. }
  11. var オプション = {
  12. 所要時間: 1500
  13. イージング: 'ease-in-out'
  14. 塗りつぶし: '前方'
  15. };
  16. offsetX = this.collDestinationX - this.ballDataList[インデックス].xとします。
  17. offsetY = this.collDestinationY - this.ballDataList[インデックス].yとします。
  18. var フレーム = [
  19. {
  20. 変身: {
  21. 翻訳: '0px 0px'  
  22. },
  23. 不透明度: 1
  24. },
  25. {
  26. 変身: {
  27. 翻訳: `${offsetX}px ${offsetY}px`
  28. },
  29. 不透明度: 0
  30. }
  31. ];
  32. アニメーションを el.animate(フレーム、オプション) とします。
  33. _t = これ
  34. アニメーション.onfinish =関数() {
  35. console.info( 'onBallClick コレクションアニメーション onFinish' );
  36. _t.isCollect = false ;
  37. _t.ballDataList.splice(インデックス, 1);
  38. console.info(JSON.stringify(_t.ballDataList));
  39.  
  40. // splice メソッドを呼び出した後、元のインデックス位置にあるボールはアニメーションしなくなるため、アニメーションを手動で作成する必要があります。
  41. if (インデックス<= _t.ballDataList.length) {
  42. setTimeout(() => {
  43. animate = _t.createShakeAnimate(el) とします。
  44. アニメーション再生()
  45. }, 5)
  46. }
  47. };
  48. this.isCollect = true  
  49. アニメーション.再生()
  50. },

7. 親コンポーネントがリセットをクリックしたら、インターフェースを更新します。

  1. onInit() {
  2. this.$watch( 'ballList' , 'onBallListChange' ); // データ変更のリスナーを登録する
  3. },
  4. onBallListChange(newV) { // 外部データが変更されたら、コンポーネントを再レンダリングします。
  5. console.log( 'onBallListChange newV = ' + JSON.stringify(newV))
  6. this.onReady()
  7. }

完全なコードは次のとおりです。

子コンポーネント:

  1. <! -- waterFlake.css -->  
  2. .main_contain {
  3. 幅: 100%;
  4. 位置:相対;
  5. }
  6.  
  7. 。ボール {
  8. 幅: 100px;
  9. 高さ: 100px;
  10. 背景色: #c3f593;
  11. 背景サイズ:100%;
  12. 境界線の半径: 60px;
  13. 境界線: #69c78e;
  14. ボーダーボトムスタイル: solid;
  15. 境界線の幅: 1px;
  16. 位置:絶対;
  17. テキスト配置: 中央;
  18. }
  19.  
  20. @keyframes 波 {
  21. から{
  22. 変換: translateY(0px);
  23. }
  24.  
  25. {
  26. 変換: translateY(10px);
  27. }
  28. }
  1. <! -- waterFlake.hml -->  
  2. <div class= "main_contain" ref= "main_contain" id= "main_contain" >
  3. <text for = "{{ ballDataList }}"  
  4. ref= "ボール{{ $idx }}"クラス= "ボール"  
  5. id= "ボール{{ $idx }}"  
  6. tid= "ボール{{ $idx }}"  
  7. onclick = "onBallClick($idx,$item)"  
  8. スタイル=": {{ $item.y }} px;
  9. : {{ $item.x }} ピクセル;
  10. >{{ $item.content } } テキスト>
  11.  
  12. </div>
  1. <! -- waterFlake.js -->  
  2. エクスポートデフォルト{
  3. 小道具: {
  4. // バックエンドから返されたボール情報
  5. ボールリスト: {
  6. デフォルト: [10, 11, 12, 13, 14],
  7. },
  8. // エネルギー収集アニメーション終了時のX座標
  9. コリジョン宛先X: {
  10. デフォルト: 0
  11. },
  12. // エネルギー収集アニメーション終了時のY座標
  13. 照合先Y: {
  14. デフォルト: 600
  15. }
  16. },
  17. データ() {
  18. 戻る{
  19. /**
  20. ballDataList 内の各オブジェクトには、次のプロパティが含まれます。
  21. * コンテンツ(ボールに表示されるテキスト情報)
  22. * x(水平座標)
  23. * y(垂直座標)
  24. /
  25. ボールデータリスト: [],
  26. isCollect: false // エネルギー収集アニメーションが現在実行中かどうか
  27. };
  28. },
  29. onInit() {
  30. this.$watch( 'ballList' , 'onBallListChange' ); // データ変更のリスナーを登録する
  31. },
  32. onReady() {
  33. let width = 720 // コンポーネントの幅
  34. let height = 600 // コンポーネントの高さ
  35. // ボールのx座標配列を生成する
  36. xRandom = this.randomCommon(1, 8, this.ballList.length) とします。
  37. all_x = xRandom.map(item => {
  38. アイテム * 幅 * 0.10を返す
  39. });
  40. // ボールのy座標配列を生成する
  41. yRandom = this.randomCommon(1, 8, this.ballList.length); とします。
  42. all_y = yRandom.map(item => {
  43. アイテム * 高さ * 0.08を返す
  44. })
  45. xランダム == null || yランダム == null場合
  46. 戻る 
  47. }
  48. データリストを [] とします
  49. for (let index = 0; index < this.ballList.length; index ++) {
  50. データリスト.push({
  51. コンテンツ: this.ballList[インデックス] + 'g'
  52. x: all_x[インデックス],
  53. y: all_y[インデックス]
  54. })
  55. }
  56. this.ballDataList = dataList; // ビューの更新をトリガーする
  57. console.info( 'onReady ballDataList = ' + JSON.stringify(this.ballDataList));
  58.  
  59. this.playShakeAnimate() // 揺れアニメーションを開始します
  60. },
  61. onBallClick(インデックス, アイテム ) {
  62. console.info( 'onBallClick index = ' + index );
  63. console.info( 'onBallClick item = ' + JSON.stringify(item));
  64. this.$emit( ​​'ballClick' , item);
  65. el = this.$element(`ball${ index }`)とします。
  66. this.playCollectionAnimate(el,インデックス)
  67. },
  68. /**
  69. * 収集したアニメーションを実行する
  70. * @param el
  71. * @paramインデックス 
  72. * @戻る 
  73. /
  74. playCollectionAnimate(el,インデックス) {
  75. if (this.isCollect) { // コレクションアニメーションが進行中の場合は、すぐに戻ります 
  76. 戻る 
  77. }
  78. var オプション = {
  79. 所要時間: 1500,
  80. イージング: 'ease-in-out'
  81. 塗りつぶし: '前方'
  82. };
  83. offsetX = this.collDestinationX - this.ballDataList[インデックス].xとします。
  84. offsetY = this.collDestinationY - this.ballDataList[インデックス].yとします。
  85. var フレーム = [
  86. {
  87. 変身: {
  88. 翻訳: '0px 0px'  
  89. },
  90. 不透明度: 1
  91. },
  92. {
  93. 変身: {
  94. 翻訳: `${offsetX}px ${offsetY}px`
  95. },
  96. 不透明度: 0
  97. }
  98. ];
  99. アニメーションを el.animate(フレーム、オプション) とします。
  100. _t = これ
  101. アニメーション.onfinish =関数() {
  102. console.info( 'onBallClick コレクションアニメーション onFinish' );
  103. _t.isCollect = false ;
  104. _t.ballDataList.splice(インデックス, 1);
  105. console.info(JSON.stringify(_t.ballDataList));
  106.  
  107. // splice メソッドを呼び出した後、元のインデックス位置にあるボールはアニメーションしなくなるため、アニメーションを手動で作成する必要があります。
  108. if (インデックス<= _t.ballDataList.length) {
  109. setTimeout(() => {
  110. animate = _t.createShakeAnimate(el) とします。
  111. アニメーション再生()
  112. }, 5)
  113. }
  114. };
  115. this.isCollect = true  
  116. アニメーション.再生()
  117. },
  118. createShakeAnimate(el) {
  119. if (el == null || el == 未定義) {
  120. 戻る 
  121. }
  122. var オプション = {
  123. 期間: 2000年、
  124. 緩和: 「摩擦」
  125. 塗りつぶし: '前方'
  126. 反復回数: 「無限」
  127. };
  128. var フレーム = [
  129. {
  130. 変身: {
  131. 翻訳: '0px 0px'  
  132. },
  133. オフセット: 0.0
  134. },
  135. {
  136. 変身: {
  137. 翻訳: '0px 20px'  
  138. },
  139. オフセット: 0.5
  140. },
  141. {
  142. 変身: {
  143. 翻訳: '0px 0px'  
  144. },
  145. オフセット: 1.0
  146. },
  147.  
  148. ];
  149. アニメーションを el.animate(フレーム、オプション) とします。
  150. リターンアニメーション
  151. },
  152. プレイシェイクアニメーション() {
  153. setTimeout(() => {
  154. console.info( 'xwg playShakeAnimate ' );
  155. for (var index = 0; index < this.ballDataList.length; index ++) {
  156. el = this.$element(`ball${ index }`)とします。
  157. animate = this.createShakeAnimate(el) とします。
  158. アニメーション再生()
  159. }
  160. }, 50)
  161. },
  162. /**
  163. * 指定された範囲から N 個の一意の番号をランダムに選択します。
  164. * 最もシンプルで基本的な方法
  165. *
  166. * @param min範囲内の最小値を指定します
  167. * @param max指定された範囲内の最大値を指定します。
  168. * @param n 乱数の数
  169. * @乱数のリストを返す
  170. /
  171. ランダムコモン(最小,最大,n){
  172. もし (n > (最大値-最小値+ 1) ||最大値<最小値) {
  173. 戻る ヌル;
  174. }
  175. 結果を [] とします。
  176. count = 0 とします。
  177. while ( count < n ) {
  178. let num = parseInt((Math.random() * ( max - min )) + min );
  179. フラグをtrueにします
  180. (j = 0; j < n; j++)の場合
  181. if (num == result[j]) {
  182. フラグ = false ;
  183. 壊す
  184. }
  185. }
  186. if (フラグ) {
  187. 結果[ count ] = num;
  188. カウント++;
  189. }
  190. }
  191. 結果を返します
  192. },
  193. onBallListChange(newV) { // 外部データが変更されたら、コンポーネントを再レンダリングします。
  194. console.log( 'onBallListChange newV = ' + JSON.stringify(newV))
  195. this.onReady()
  196. }
  197. }

親コンポーネント:

  1. <! --index.css -->  
  2. 。容器 {
  3. flex-direction:;
  4. align-items: flex-start;
  5. }
  6.  
  7. 。タイトル {
  8. フォントサイズ: 100px;
  9. }
  10.  
  11. .forestContainer {
  12. 幅: 100%;
  13. 高さ: 750px;
  14. 背景画像: url( "/common/bg.jpg" );
  15. 背景サイズ:100%;
  16. background-repeat: -repeatなし;
  17. }
  1. <! -- index.html -->  
  2. <要素= 'waterFlake' src = '../../../default/common/component/waterflake/waterFlake.hml' ></要素>
  3. <div クラス = "コンテナ" >
  4. <div クラス = "forestContainer" >
  5. <waterFlake ボールリスト = "{{ ballList }}" @ボールクリック = "onBallClick" ></waterFlake>
  6. </div>
  7. <button style= "padding : 20px; align-content : center; background-color : #222222;"  
  8. onclick= "reset" >リセット
  9. </ボタン>
  10.  
  11. </div>
  1. <! --index.js -->  
  2. インポートプロンプト  '@system.prompt' ;
  3. エクスポートデフォルト{
  4. データ() {
  5. 戻る{
  6. ボールリスト: []
  7. }
  8. },
  9. onInit() {
  10. this.ballList = this.genRandomArray(5);
  11. },
  12. onBallClick(情報) {
  13. console.info( 'xwg 親 onBallClick 項目 = ' + JSON.stringify(info.detail));
  14. コンテンツ = info.detail.content とします
  15. prompt.showToast({message:`${content} をクリックしました`,duration:1500})
  16. },
  17. リセット(){
  18. console.info( "xwg リセットがクリックされました " )
  19. this.ballList = this.genRandomArray(6);
  20. console.info( "xwg リセット ballList = " + JSON.stringify(this.ballList))
  21. },
  22. genRandomArray(カウント) {
  23. ballArray = [] とします
  24. for (var index = 0; index < count ; index ++) {
  25. v = this.random(1, 60) とします。
  26. ballArray.push(parseInt(v))
  27. }
  28. ballArrayを返す
  29. },
  30. ランダム(最小,最大){
  31. Math.floor(Math.random() * ( max - min )) + minを返します
  32. }
  33. }

詳細については、以下をご覧ください。

51CTOとHuaweiが共同で構築したHarmonyOSテクノロジーコミュニティ。

https://harmonyos..com