![](https://habrastorage.org/getpro/habr/post_images/f85/44f/bbf/f8544fbbf739316fa9c3b7984dbbd53b.png)
現在まで、リッチクライアントアプリケーションを作成するためのJavaScriptライブラリが多数あります。 有名なKnockout、Angular.JS、Emberに加えて、他にも非常に多くのフレームワークがあり、それぞれが独自の特性を持っています-誰かがミニマリズムを促進し、誰かが-イデオロギーの純粋さとMVCの哲学への準拠。 この多様性により、ますます多くの新しいライブラリが定期的に登場しています。 habr - Warp9とMatreshka.jsで言及された最後から。 この点で、私は自分のクラフトについてお話ししたいと思います。JohnSmith -UIを構築するためのシンプルで軽量なJavaScriptフレームワークです。
まず第一に、JohnSmithは学問的利益のために書かれたものではなく、致命的な欠陥を排除するものではないと言いたいと思います。 それどころか、JohnSmithは実際のプロジェクトで始まり、プロジェクトからプロジェクトに移行し、徐々にその形を改善し、変化させました。 そして今、それは本格的なオープンソースライブラリとして具体化しました。
例
JohnSmithの機能を示すために、次の機能を備えたシンプルなアプリケーションを作成します。
ユーザーが自分の名前を入力する入力フィールドがあります。 名前が入力されるとすぐに、メッセージHello、%username%が表示されます。
誰がすぐに結果を見たいのか:完成したユーザーGreeterは次のとおりです。
モデルを見る
ビューモデルを作成することから始めましょう。まず、「クラス」を作成します。
var GreeterViewModel = function(){ }
ビューモデルは通常、変更を外部から追跡できる外部の世界オブジェクトに「露出」します。 JohnSmithでは、これらのオブジェクトはバインド可能と呼ばれます。 ユーザー名を保存するフィールドを追加します。
var GreeterViewModel = function(){ this.userName = js.bindableValue(); };
このフィールド(
userName
)は、ビューでの双方向リンクに使用されます。 メッセージテキストを形成する別のフィールドを追加します。 このフィールドは
userName
に依存するため、
dependentValue
として説明します。
var GreeterViewModel = function(){ this.userName = js.bindableValue(); this.greetMessage = js.dependentValue( this.userName, function(userNameValue){ if (userNameValue) { return "Hello, " + userNameValue + "!"; } return "Please, enter your name"; }); };
js.dependentValueは、JohnSmithで依存関係を手動で指定することを除いて、ノックアウトで計算されたものに似ています。 舞台裏では、自動追跡の魔法はありません。
Viewモデルの準備ができました。次に、Viewについて説明します。
表示する
クラスを作成することから始めましょう:
var GreeterView = function(){ }
ビューは、マークアップと、このマークアップと外界との接続のロジックの組み合わせです。 マークアップは
template
フィールドで説明され、ロジックは
init
メソッドで説明され
init
。
var GreeterView = function(){ this.template = "... ..."; this.init = function(){ // } };
このテスト例では、マークアップは非常に単純なので、テンプレートフィールドに直接書き込みます。
var GreeterView = function(){ this.template = "<p>Enter your name: <input type='text'/></p>" + "<p class='message'></p>"; this.init = function(){ // }; };
次に、
init
メソッドに進み
init
。 まず、JohnSmithは、各ビューが特定のビューモデルで機能することを暗示しているため、viewModelパラメーターを追加します。
var GreeterView = function(){ this.template = "<p>Enter your name: <input type='text'/></p>" + "<p class='message'></p>"; this.init = function(viewModel){ // <--- // }; };
さらに、ビューモデルのプロパティを、ビューが描画するマークアップに接続します。 JohnSmithは、この関連付けをjsコードで直接構成するための構文を提供します。 この場合、次のようになります。
var GreeterView = function(){ this.template = "<p>Enter your name: <input type='text'/></p>" + "<p class='message'></p>"; this.init = function(viewModel){ this.bind(viewModel.userName).to("input"); // <--- this.bind(viewModel.greetMessage).to(".message"); // <--- }; };
これですべての準備が整い、ビューを描画するだけです(ページにid = 'greeter'の要素があることが理解されます):
js.renderView(GreeterView, new GreeterViewModel()).to("#greeter");
これで、ガジェットが完成しました 。結果はここで見ることができます 。 この例は、フレームワークの基本的な哲学を示していますが、JohnSmithの機能についてさらに学習するために、いくつかの詳細を明確にします。
バインディング
JohnSmithのバインディングの基礎は、オブザーバブルオブジェクトです(ノックアウトなど)。 これらのオブジェクトは、次のいずれかの方法を使用して作成されます。
-
js.bindableValue
通常のjs.bindableValue
可能なオブジェクト。 -
js.dependentValue
他のオブジェクトに依存する値。 -
js.bindableList
-observable-collection。要素の追加/削除についてサブスクライバーに通知します。
オブジェクトAとリスナーBの直接リンクは、次の形式のコードで構成されます。
js.bind(A).to(B);
たとえば、次のように:
var firstName = js.bindableValue(); // js.bind(firstName).to(".firstName"); // jQuery- firstName.setValue("John"); //
ビュー内では、バインディングコードが少し変更されます。
// init this.bind(viewModel.firstName).to(".firstName");
この場合、
.firstName
セレクターの検索は、このViewのマークアップ内でのみ機能し、ドキュメント全体では機能しません。 これにより、外部環境からビューを完全に独立させることができます。
構文
js.bind(A).to(B)
使用すると、「宣言型」スタイルと命令型を組み合わせて、必要な場合にjQueryスタイルを使用できます。
// : js.bind(firstName).to(".firstName"); js.bind(firstName).to( function(newValue, oldValue){ // <-- // jQuery , // , / - // newValue/oldValue, , .. });
通常の(観測不可能な)値をバインド可能なオブジェクトとして渡すと、インターフェイスとの1回限りの同期が発生します。 これにより、観察可能なビューモデルフィールドと「通常の」ビューモデルフィールドの両方を同じ方法で処理できます。
var ViewModel = function(){ this.firstName = "John"; // static value this.lastName = js.bindableValue(); // observable value }; //... // somewhere in the View: this.bind(viewModel.firstName).to(".firstName"); // will sync only once this.bind(viewModel.lastName).to(".lastName"); // will sync on every change
複雑なオブジェクトを描画するには、子ビューを使用できます。
var ViewModel = function(){ this.myAddress = js.bindableValue(); this.initState = function(){ this.myAddress.setValue({ country: 'Russia', city: js.bindableValue(); }); }; }; // ... this.bind(viewModel.myAddress).to(".address", AddressView); // ...
ビュー構成
JohnSmithのビューは、インターフェースを構築するための原子単位です。 各ビューは完全に独立しており、再利用の可能性を提供します。 アプリケーション全体のインターフェースは、「ツリー」( 複合パターン )を構築することにより、個別のビューで構成されます。 つまり、メインビューが1つあり、子ビューがあり、各子には独自のビューがあります。 構成は、いくつかの方法で実現されます。
- 子ビューの直接追加:
var ParentView = function(){ this.init = function(){ this.addChild(".destination", new ChildView(), new ChildViewModel()); // <-- } };
- ビューを使用してバインド可能な値を描画します。
var ParentView = function(){ this.init = function(viewModel){ this.bind(viewModel.details).to(".details", DetailsView); // <-- } };
複合ビューの小さなデモンストレーションとして、ファイルツリーは次のことを行います。
![](https://habrastorage.org/getpro/habr/post_images/285/f21/3d6/285f213d6a6d8d13a5752dfad1e5dad9.png)
おわりに
結論として、JohnSmithの機能を示します。
- UIの互換性により、あらゆるサイズのプロジェクトでJohnSmithを簡単に使用できます。 同時に、複雑さが増すにつれて、コードを制御しやすくなります。 これは、モジュール性と、ビューとモデルの間の責任の明確な分割によって達成されます。
- JohnSmithは非常にシンプルです-基本的な概念は2つしかなく(ViewとBindable)、UIを使用したプログラマーにはよく知られています。 パラダイムシフトも舞台裏の魔法もありません。
- JohnSmithは、通常のフィールドとメソッドを持つ通常のオブジェクトで動作します。 これは、小文字の識別子に依存するアクション(
model.set('firstName', 'John')
)を実行する必要がないことを意味します。 このアプローチにより、IDEとの親密な関係が確保され、 TypeScriptやScriptSharpなどのツールとの相性がよくなります。 - JohnSmithはJavaScriptコードからDOM要素を操作するため、jQueryが必要です。
githubのリポジトリ
それだけです、あなたの注意をありがとう、建設的な批判を待っています!