Ember.js:優れたWebアプリケーションフレームワーク

Ember.jsは、Webアプリケーションのクライアントサイドを開発するためのJavaScriptフレームワークであり、最近注目を集めている野心的なプロジェクトです。 今日は、Ember.jsの基礎となる重要な概念のいくつかについてお話しし、シンプルなアプリケーションの作成中にそれらを実証します。







これはサイコロローラープログラムで、サイコロを「ロール」し、パラメーターを事前に設定し、以前の「ロール」の履歴を表示できます。 彼女のコードはGithubにあります。



Ember.jsフレームワークには、JavaScriptの世界の多くの最新のコンセプトとテクノロジーが含まれています。 その機能の中で、私は次のことに注意したいと思います。





Ember.jsの使用を開始するには、Node.jsとnpmの最新バージョンが必要です。 これはすべてNode.jsからダウンロードできます



さらに、Ember.jsはフロントエンド指向のフレームワークであると言う価値があります。 さまざまなバックエンドと対話する多くの方法をサポートしていますが、サーバーコードに関連するすべてのことはEmberの責任ではありません。



ember-cliの紹介



Ember.jsコマンドラインインターフェースember-cli



は、このフレームワークの多くの機能へのアクセスを提供します。 Ember-cli



は、作業のすべての段階でプログラマーをサポートします。 アプリケーションの作成、機能の拡張、テストおよび開発モードでのプロジェクトの起動を簡素化します。



Emberアプリケーションの作成中に行うことのほとんどすべてに、ある程度までember-cli



使用が含まれます。 したがって、このツールを研究することが重要です。 私たちは、教育プロジェクトの作業中、常にそれを使用します。



作業の最初のステップは、 ember-cli



をインストールすることです。すでにインストールされている場合は、既存のバージョンの関連性を確認します。 次のコマンドを使用して、 npm



レジストリからember-cli



をインストールできます。



 $ npm install -g ember-cli
      
      





インストールが成功したかどうかを確認し、同時にインストールされているember-cli



バージョンを確認するには、次のコマンドを使用できます。



 $ ember --version ember-cli: 2.15.0-beta.1 node: 8.2.1 os: darwin x64
      
      





Ember.jsでの最初のアプリケーションの作成



ember-cli



インストール後、アプリケーションの作成を開始できます。 これは、 ember-cli



を使用する最初の状況です。 彼は、アプリケーションの構造を作成し、構成し、作業プロジェクトを提供します。 次のコマンドを使用して、 dice-roller



アプリケーションを作成します。



 $ ember new dice-roller installing app create .editorconfig create .ember-cli create .eslintrc.js create .travis.yml create .watchmanconfig create README.md create app/app.js create app/components/.gitkeep create app/controllers/.gitkeep create app/helpers/.gitkeep create app/index.html create app/models/.gitkeep create app/resolver.js create app/router.js create app/routes/.gitkeep create app/styles/app.css create app/templates/application.hbs create app/templates/components/.gitkeep create config/environment.js create config/targets.js create ember-cli-build.js create .gitignore create package.json create public/crossdomain.xml create public/robots.txt create testem.js create tests/.eslintrc.js create tests/helpers/destroy-app.js create tests/helpers/module-for-acceptance.js create tests/helpers/resolver.js create tests/helpers/start-app.js create tests/index.html create tests/integration/.gitkeep create tests/test-helper.js create tests/unit/.gitkeep create vendor/.gitkeep NPM: Installed dependencies Successfully initialized git. $
      
      





上記のコマンドを実行すると、実行可能なアプリケーションレイアウトが作成されます。 彼女はGitバージョン管理も設定しました。 Gitとの統合をオフにすることができ、さらに、 npm



パッケージマネージャーの代わりにyarn



を使用できることに注意してください。 詳細については、Emberのドキュメントをご覧ください。



では、得られたものを見てみましょう。 すでに述べたように、開発用のEmberアプリケーションの起動は、 ember-cli



を使用して実行されます。 これは次のように行われます。



 $ cd dice-roller $ ember serve Livereload server on http://localhost:49153 'instrument' is imported from external module 'ember-data/-debug' but never used Warning: ignoring input sourcemap for vendor/ember/ember.debug.js because ENOENT: no such file or directory, open '/Users/coxg/source/me/writing/repos/dice-roller/tmp/source_map_concat-input_base_path-2fXNPqjl.tmp/vendor/ember/ember.debug.map' Warning: ignoring input sourcemap for vendor/ember/ember-testing.js because ENOENT: no such file or directory, open '/Users/coxg/source/me/writing/repos/dice-roller/tmp/source_map_concat-input_base_path-Xwpjztar.tmp/vendor/ember/ember-testing.map' Build successful (5835ms) – Serving on http://localhost:4200/ Slowest Nodes (totalTime => 5% )              | Total (avg) ----------------------------------------------+--------------------- Babel (16)                                    | 4625ms (289 ms) Rollup (1)                                    | 445ms
      
      





これですべての準備が整いました。アプリケーションはhttp:// localhost:4200で利用でき、次のようになります。







アプリケーション自体に加えて、 LiveReloadサービスが起動され 、プロジェクトファイルへの変更を監視し、ブラウザーのページを自動的にリロードします。 これは、サイトの変更中に、変更の結果が非常にすばやく表示されることを意味します。



最初のページでは、次に何ができるか、これらのメッセージを聞いて、メインページを変更し、何が起こるかを確認します。 これを行うには、ファイルapp/templates/application.hbs



を次のフォームにapp/templates/application.hbs



します。



 This is my new application. {{outlet}}
      
      





{{outlet}}



タグは、Emberでのルーティングプロセスの仕組みの一部であることに注意してください。 これについては、以下で詳しく説明します。



ファイルを変更した後、すぐにコンソールに表示されるember-cli



確認する必要があります。 次のようになります。



 file changed templates/application.hbs Build successful (67ms) – Serving on http://localhost:4200/ Slowest Nodes (totalTime => 5% )              | Total (avg) ----------------------------------------------+--------------------- SourceMapConcat: Concat: App (1)              | 9ms SourceMapConcat: Concat: Vendor /asset... (1) | 8ms SimpleConcatConcat: Concat: Vendor Sty... (1) | 4ms Funnel (7)                                    | 4ms (0 ms)
      
      





ここで、システムがテンプレートの変更を検出し、プロジェクトを再構築して再起動したことが通知されます。 これは完全に自動化されたプロセスであり、参加していません。



次に、ブラウザを見てみましょう。 LiveReload



インストールして実行している場合、変更を確認するためにページを手動でリロードする必要はありません。 それ以外の場合、アプリケーションページはそれ自体でリロードする必要があります。







これは、ページの外観が驚くべきものであると言うことではありませんが、それを使って行ったことは、私たちの側で最小限の努力を必要としました。



さらに、完全にテストされたテストサブシステムがあります。 それを実行するには、適切なEmberツールを使用する必要があります。



 $ ember test ⠸ Building'instrument' is imported from external module 'ember-data/-debug' but never used ⠴ BuildingWarning: ignoring input sourcemap for vendor/ember/ember.debug.js because ENOENT: no such file or directory, open '/Users/coxg/source/me/writing/repos/dice-roller/tmp/source_map_concat-input_base_path-S8aQFGaz.tmp/vendor/ember/ember.debug.map' ⠇ BuildingWarning: ignoring input sourcemap for vendor/ember/ember-testing.js because ENOENT: no such file or directory, open '/Users/coxg/source/me/writing/repos/dice-roller/tmp/source_map_concat-input_base_path-wO8OLEE2.tmp/vendor/ember/ember-testing.map' cleaning up... Built project successfully. Stored in "/Users/coxg/source/me/writing/repos/dice-roller/tmp/class-tests_dist-PUnMT5zL.tmp". ok 1 PhantomJS 2.1 - ESLint | app: app.js ok 2 PhantomJS 2.1 - ESLint | app: resolver.js ok 3 PhantomJS 2.1 - ESLint | app: router.js ok 4 PhantomJS 2.1 - ESLint | tests: helpers/destroy-app.js ok 5 PhantomJS 2.1 - ESLint | tests: helpers/module-for-acceptance.js ok 6 PhantomJS 2.1 - ESLint | tests: helpers/resolver.js ok 7 PhantomJS 2.1 - ESLint | tests: helpers/start-app.js ok 8 PhantomJS 2.1 - ESLint | tests: test-helper.js 1..8 # tests 8 # pass  8 # skip  0 # fail  0 # ok
      
      





出力の大部分はPhantom.jsからのものであることに注意してください。 これは、統合テストが完全にサポートされているためです。デフォルトでは、グラフィカルインターフェイスなしでPhantomJSブラウザーで実行されます。 必要に応じて、他のブラウザーでテストを実行する機能もあります。 継続的インテグレーションシステム(CI、継続的インテグレーション)をセットアップする場合、この機会を利用して、サポートされているすべてのブラウザーでアプリケーションが正しく動作することを確認する必要があります。



Ember.jsアプリケーションの構造



アプリケーションの作業を開始する前に、その基になるフォルダーとファイルの構造を理解します。 上記のember new



コマンドは、アプリケーションに必要なフォルダーとファイルを作成しますが、その中にはかなりの数があります。 Emberを使用して効果的な作業を編成し、あらゆる規模のプロジェクトを作成するには、すべてがどのように機能するかを理解することが重要です。



アプリケーション構造の最高レベルでは、次のファイルとフォルダーに注意を払うことができます。





ページ構造



続行する前に、ページの構造を見てみましょう。 この場合、 Materialize CSSフレームワークを使用します。これにより、ページの見栄えが良くなり、エンドユーザーにとってより便利に作業できるようになります。



アプリケーションに追加のツールのサポートを追加するには、次のいずれかの方法を使用できます。





残念ながら、マテリアライズのアドオンはEmber.jsの最新バージョンではまだ動作しないため、CDNリソースへのリンクを使用して、アプリケーションのメインページでこのフレームワークを接続します。 これを行うには、 app/index.html



ファイルを編集する必要があります。このファイルには、アプリケーションが表示されるメインページの構造が記述されています。 CDNリンクをjQuery、Googleアイコン付きフォント、およびMaterializeに追加します。



 <!-- Inside the Head section -->   <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">   <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.1/css/materialize.min.css"> <!-- Inside the Body section -->   <script type="text/javascript" src="https://code.jquery.com/jquery-3.2.1.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.1/js/materialize.min.js"></script>
      
      





メインページを変更して、アプリケーションの基本テンプレートを表示できるようになりました。 これは、ファイルapp/templates/application.hbs



を次の形式に変換することにより行われます。



 <nav>   <div class="nav-wrapper">       <a href="#" class="brand-logo">           <i class="material-icons">filter_6</i>           Dice Roller       </a>       <ul id="nav-mobile" class="right hide-on-med-and-down">       </ul>   </div> </nav> <div class="container">   {{outlet}} </div>
      
      





このコードのおかげで、マテリアライズツールによって準備されたナビゲーションバーがページの上部に表示されます。 上記の{{outlet}}



タグが配置されているページにもコンテナーがあります。



これで、ブラウザを見ると、ページが下の図に示すようになっていることがわかります。







{{outlet}}



タグについて説明します。 Emberの作業はルートベースです。 各ルートは、他のルートの子孫と見なされます。 ルートルートは自動的に処理され、テンプレートapp/templates/application.hbs



表示されapp/templates/application.hbs







{{outlet}}



タグは、Emberが現在の階層の次のルートに対応するコンテンツを表示する場所を設定します。その結果、第1レベルのルートはapplication.hbs



このタグに表示され、第2レベルのルートは第1レベルテンプレートの同じタグに表示され、さらに。



新しいルートを作成する



Ember.js上のアプリケーションの各ページへのアクセスは、ルート(ルート)で整理されています。 ブラウザが開くURLと、アプリケーションが表示するルートに関連する資料との間には直接的な対応があります。



この概念を理解する最も簡単な方法は、例を使用することです。 ユーザーがサイコロを「転がす」ことを許可する新しいルートをアプリケーションに追加します。 このステップも、 ember-cli



を使用して実行されます。



 $ ember generate route roll installing route create app/routes/roll.js create app/templates/roll.hbs updating router add route roll installing route-test create tests/unit/routes/roll-test.js
      
      





このコマンドを呼び出して作成されたものは次のとおりです。





仕組みを見てみましょう。 これまでのところ、サイコロとボタンを説明する要素を含む非常にシンプルなページがあり、少し後に「投げる」ことができます。 このページを作成するには、テンプレートファイルapp/templates/roll.hbs



次のコードを挿入します。



 <div class="row">   <form class="col s12">       <div class="row">           <div class="input-field col s12">               <input placeholder="Name" id="roll_name" type="text" class="validate">               <label for="roll_name">Name of Roll</label>           </div>       </div>       <div class="row">           <div class="input-field col s6">               <input placeholder="Number of dice" id="number_of_dice" type="number" class="validate" value="1">               <label for="number_of_dice">Number of Dice</label>           </div>           <div class="input-field col s6">               <input placeholder="Number of sides" id="number_of_sides" type="number" class="validate" value="6">               <label for="number_of_sides">Number of Sides</label>           </div>       </div>       <div class="row">           <button class="btn waves-effect waves-light" type="submit" name="action">               Roll Dice               <i class="material-icons right">send</i>           </button>       </div>   </form> </div> {{outlet}}
      
      





その後、 http:// localhost:4200 / rollページにアクセスして、何が起こるかを確認します。







ここで、アプリケーションインターフェイスを介してこのページへの移行を整理する方法が必要です。 Emberは、 link-to



タグを使用してこのタスクを簡素化します。 特に、ユーザーに送信するルートの名前を受け入れ、ユーザーがこのルートをたどることができる要素を表示します。



app/templates/application.hbs



ファイルに次を含めます。



 <ul id="nav-mobile" class="right hide-on-med-and-down">   {{#link-to 'roll' tagName="li"}}       <a href="roll">Roll Dice</a>   {{/link-to}} </ul>
      
      





これにより、ページ上部のナビゲーションバーが次の図に示す形式になります。







新しいリンクRoll Dice



がパネルの右側に表示され、クリックすると、ユーザーは/roll



ルートをたどります。 それが私たちが達成しようとしたことです。



モジュラーコンポーネント開発



アプリケーションで作業しようとすると、試してみてください、問題に気づくでしょう。 ホームページは正常に開き、 /roll



リンクは機能しますが、フォームのフィールドラベルが正しく配置されていません。 これは、Materializeが要素を適切に配置するために特定のJSコードを呼び出す必要があるためですが、動的ルーティングの機能により、ページはリロードされません。 今それを修正します。



コンポーネントを操作しましょう。 コンポーネントは、ユーザーインターフェースのフラグメントであり、相互作用できる完全なライフサイクルを持っています。 さらに、コンポーネントを使用すると、必要に応じて、再利用に適したユーザーインターフェイス要素を作成できます。 これについては後で説明します。



次に、 Roll Dice



フォームである唯一のコンポーネントを作成します。 そのような状況ではいつものように、コンポーネントを作成するために、 ember-cli



を見てみましょう。



 $ ember generate component roll-dice installing component create app/components/roll-dice.js create app/templates/components/roll-dice.hbs installing component-test create tests/integration/components/roll-dice-test.js
      
      





その結果、システムは以下を作成します。





次に、すべてのマークアップをコンポーネントに移動します。 これは、アプリケーションの動作に直接影響を与えることはありませんが、将来、必要な方法で構成するのに役立ちます。

ファイルapp/templates/components/roll-dice.hbs



をこの状態にします:



 <form class="col s12">   <div class="row">       <div class="input-field col s12">           <input placeholder="Name" id="roll_name" type="text" class="validate">           <label for="roll_name">Name of Roll</label>       </div>   </div>   <div class="row">       <div class="input-field col s6">           <input placeholder="Number of dice" id="number_of_dice" type="number" class="validate" value="1">           <label for="number_of_dice">Number of Dice</label>       </div>       <div class="input-field col s6">           <input placeholder="Number of sides" id="number_of_sides" type="number" class="validate" value="6">           <label for="number_of_sides">Number of Sides</label>       </div>   </div>   <div class="row">       <button class="btn waves-effect waves-light" type="submit" name="action">           Roll Dice           <i class="material-icons right">send</i>       </button>   </div> </form>
      
      





app/templates/roll.hbs



次のコードをapp/templates/roll.hbs







 <div class="row">   {{roll-dice}} </div> {{outlet}}
      
      





以前にルートテンプレートファイルに配置されていた同じマークアップが、コンポーネントテンプレートに分類されました。 ルートテンプレートファイルがはるかに単純になりました。 roll-dice



タグは、Emberにコンポーネントを配置する場所を伝えます。



ブラウザでアプリケーションがどのように見えるかを今見ても、違いは見られません。 ただし、コードデバイスは変更され、モジュール化されています。 間違ったページレイアウトを修正し、アプリケーションにいくつかの新機能を追加するために、作成したコンポーネントを使用します。



コンポーネントのライフサイクル



Emberのコンポーネントには特別なライフサイクルがあり、ライフサイクルのさまざまな段階でフックが呼び出されます。 マテリアライズが署名を正しく表示できるようにするには、コンポーネントが表示された後に呼び出されるdidRender



フックを使用します。 さらに、これはコンポーネントの最初のショーとその後のディスプレイの両方で行われます。



これを行うには、ファイルapp/components/roll-dice.js



あるコンポーネントコードを編集します。



 /* global Materialize:false */ import Ember from 'ember'; export default Ember.Component.extend({   didRender() {       Materialize.updateTextFields();   } });
      
      





これで、ダイレクトリンクまたはナビゲーションパネルからのリンクを使用して/roll



ルートにアクセスするたびに、このコードが実行され、マテリアライズはテキストフィールドの署名を正しく表示します。



データバインディング



コンポーネントを使用して、データをユーザーインターフェイスにロードし、そこからアンロードします。 これは非常に簡単ですが、興味深いことに、Emberマニュアルにはこれについて何もありません。 その結果、Emberのデータバインディング手順は実際よりも複雑に見えます。



処理するデータの各部分は、 Component



クラスのフィールドの形式で存在します。 これを知って、コンポーネントの入力フィールドを表示し、これらのフィールドをコンポーネント変数にバインドできる補助ツールを使用できます。 その結果、DOMを使用することを考えずに、データを直接操作できます。



この場合、3つのフィールドがあるため、コンポーネント定義ブロック内のapp/components/roll-dice.js



に3行のコードを追加する必要があります。



     rollName: '',   numberOfDice: 1,   numberOfSides: 6,
      
      





次に、通常のHTMLマークアップの代わりに補助メカニズムを使用してこのデータを出力するようにテンプレートを構成します。 これを行うには、 <input>



を次のコードに置き換える必要があります。



 <div class="row">   <div class="input-field col s12">       <!-- This replaces the <input> tag for "roll_name" -->       {{input placeholder="Name" id="roll_name" class="validate" value=(mut rollName)}}       <label for="roll_name">Name of Roll</label>   </div> </div> <div class="row">   <div class="input-field col s6">       <!-- This replaces the <input> tag for "number_of_dice" -->       {{input placeholder="Number of dice" id="number_of_dice" type="number" class="validate" value=(mut numberOfDice)}}       <label for="number_of_dice">Number of Dice</label>   </div>   <div class="input-field col s6">       <!-- This replaces the <input> tag for "number_of_sides" -->       {{input placeholder="Number of sides" id="number_of_sides" type="number" class="validate" value=(mut numberOfSides)}}       <label for="number_of_sides">Number of Sides</label>   </div> </div>
      
      





value



属性の構文は異常に見えることに注意してください。 同様の構成は、 value



だけでなく、任意のタグ属性に使用できvalue



。 それらを使用する3つの方法を次に示します。





, , , Ember.





. , Roll Dice



. Ember (Actions). — , . — , , , , actions



.



, , ( ). OnSubmit



. , , Enter



.



, , app/components/roll-dice.hbs



:



     actions: {       triggerRoll() {           alert(`Rolling ${this.numberOfDice}D${this.numberOfSides} as "${this.rollName}"`);           return false;       }   }
      
      





false



. — , HTML-. .



, , . DOM — , — JS-.



. , onsubmit



. Ember . app/templates/components/roll-dice.hbs



:



 <form class="col s12" onsubmit={{action 'triggerRoll'}}>
      
      





, , , , .









, - «» . . «» . :





, , Ember .



Ember (Store), (Models). — , (Model) , . , , .





. ( , ), . .



, , — . , , , , , . , DOM Ember , - .



, , , , . , , .



, , , app/routes/roll.js



, , , .



 actions: {   saveRoll: function(rollName, numberOfDice, numberOfSides) {       alert(`Rolling ${numberOfDice}D${numberOfSides} as "${rollName}"`);   } }
      
      





, app/components/roll-dice.js



, . sendAction



:



 triggerRoll() {   this.sendAction('roll', this.rollName, this.numberOfDice, this.numberOfSides);   return false; }
      
      





, , , . — app/templates/roll.hbs



. , :



 {{roll-dice roll="saveRoll" }}
      
      





, roll



saveRoll



. , roll



, , , «» . , , «» , , .



, , , , , , .





, , . ember-cli



.



, , :



 $ ember generate model roll installing model create app/models/roll.js installing model-test create tests/unit/models/roll-test.js
      
      





, . app/models/roll.js



:



 import DS from 'ember-data'; export default DS.Model.extend({   rollName: DS.attr('string'),   numberOfDice: DS.attr('number'),   numberOfSides: DS.attr('number'),   result: DS.attr('number') });
      
      





DS.attr



. — string



, number



, date



boolean



, , .



, «» . , app/routes/roll.js



:



 saveRoll: function(rollName, numberOfDice, numberOfSides) {   let result = 0;   for (let i = 0; i < numberOfDice; ++i) {       result += 1 + (parseInt(Math.random() * numberOfSides));   }   const store = this.get('store');   //      "roll"  .   const roll = store.createRecord('roll', {       rollName,       numberOfDice,       numberOfSides,       result   });   //      ,      .   roll.save(); }
      
      





, , Roll Dice



. , , , , , — .







Ember.js, . Ember.js , , , ember-localstorage-adapter , . . , .





, - , . , index



— .



Ember , index



, . , , , . «» .



index



, ember-cli



. .



app/routes/index.js



, :



 import Ember from 'ember'; export default Ember.Route.extend({   model() {       return this.get('store').findAll('roll');   } });
      
      





findAll



«» . , model



.



index app/templates/index.hbs



:



 <table>   <thead>       <tr>           <th>Name</th>           <th>Dice Rolled</th>           <th>Result</th>       </tr>   </thead>   <tbody>   {{#each model as |roll|}}       <tr>           <td>{{roll.rollName}}</td>           <td>{{roll.numberOfDice}}D{{roll.numberOfSides}}</td>           <td>{{roll.result}}</td>       </tr>   {{/each}}   </tbody> </table> {{outlet}}
      
      





, . «»:





まとめ



, , , , «» . , , , . .



Ember . , , React, Ember , - . ember-cli



— , . , , Ember , .



Ember . , Ember . , , « », Ember . Ember, , , ( ) , , .



Ember — , -. , , , , , .

親愛なる読者! Ember.js?



All Articles