base.jsでのクールな単一ページアプリケーションの作成-パート1、入門理論

すべての人に良い一日を!

この記事は、本格的な単一ページアプリケーションを作成するためのフレームワークである、basis.jsに特化した一連の出版物から始まります。





フレームワークについて



最新のフロントエンドフレームワークのコアは、コレクションを処理するための構造とアルゴリズムを持たないため、実際にはデータの操作を指向していません。

代わりに、開発者には、データを独立して操作し、テンプレートでコレクションを直接反復するか、コントローラー/コンポーネントコードから直接DOM要素を操作する機会が与えられます。

このようなアプローチの欠点は明らかです。

コントローラー/コンポーネントからDOM要素を操作する場合:

-データセットを処理するためのデータ構造とアルゴリズムを個別に実装する必要があります

-DOM要素を手動で操作し、データとDOM要素間の関係を確立する必要があるため、コードの複雑さと保守性が向上します。

-ほとんどの場合、テンプレートエンジンを使用することはできません



データセットの操作でテンプレートエンジンを使用する場合:

-ロジックがテンプレートに部分的に転送されるため、テンプレートの可読性が損なわれます

-表現の一部を更新するメカニズムは、テンプレートエンジンで効果的に実装されていますか?

-データセットを処理するためのメカニズムはまだありません



以前は、バックエンドがデータの処理とその視覚的なプレゼンテーションを担当していたため、これは実質的には重要ではありませんでした。

必要なことは、目的のアドレスにページをロードすることだけで、プレゼンテーションはすでに形成されていました。

このアプローチの欠点は、データの更新という点で対話性とダイナミズムが欠如していることです。

最新のSPAは、機能の点で自律的であり、データの同期(新しいデータの保存または受信)が必要な場合にのみサーバーにアクセスする必要があります。

したがって、このデータの処理と視覚化に関するすべての作業は、フロントエンドで行う必要があります。

AJAXとWebSocketの登場により、データの更新を監視し、アプリケーションの対話性を確保することがはるかに簡単になりました。

ただし、AJAXとWebSocketはネットワークを操作するためのものであり、データを操作するという基本的な問題は解決しません。



VKontakteのクライアントである1ページのアプリケーションを作成しているとします。

アプリケーションの要件の一部は次のとおりです。ダウンロード、更新、検索、グループ化、ソーシャルネットワークからの友人の並べ替え。

次に、「音楽」セクションが追加されます。 ここでは、すでにプレイリスト(自分と友人の両方)で作業する必要があります。 同じ検索。

「メッセージ」セクションが追加されます。 「部屋」とメッセージを扱う作業があります。

意味は明確だと思います...

音楽、友達、メッセージなど-並べ替え、グループ化、検索、最後に視覚化するために必要なすべてのデータです。 同時に、視覚的表現はリアルタイムでタイムリーに更新される必要があります。



したがって、開発者の武器には、理論的にはあらゆる量のデータを処理するための強力で便利なツールが必要です。



テンプレートエンジンについて



別のホリバーを繁殖させないために、特定の人気のあるフレームワークを例として挙げません。 代わりに、柔軟で便利なテンプレートエンジンを備えた特定の抽象的なフレームワークがあることを想像してください。

上記のSPAのタスクをどのように解決しますか?

非常にシンプル-ソーシャルネットワークサーバーからデータをダウンロードし、フレームワークテンプレートエンジンにフィードします。

まあ、私たちは、撤退の問題を解決したようです。

ただし、すでに描画済みのコレクションに新しい要素が追加されていることがわかりました。

どうする

繰り返しますが、すべてが非常に単純です-ビューを再描画するようにテンプレートエンジンに依頼しますが、新しいデータを使用します。

そして、データがあまりない限り、すべてがうまくいくようです。

サーバーから受け取った100個のオブジェクトのコレクションがあるとします。

このデータをテンプレートエンジンに渡し、彼は忠実にレンダリングしましたが、しばらくすると、サーバーは別の要素がコレクションに追加されたことを通知します。

何してるの? 繰り返しますが、テンプレートエンジンにデータを渡すと、彼は注意して、以前にレンダリングしたすべてのデータを再描画します。

あまり効果的ではありませんか? 特にコレクション内にさらに要素がある場合。

ここでは、テンプレートとデータを入力として受け取り、DOMに挿入する必要があるHTMLコードを含む行を出力する文字列テンプレートエンジンについて説明していることに注意してください。

しかし、これらはHTMLとDOMについてまったくわからない文字列ステンシルでもあります。 彼らはどのデータをどのテンプレートに挿入し、開発者がこのデータをどう処理するかを気にしません。



スマートテンプレートエンジンについて



通常の文字列テンプレートエンジンとは対照的に、よりインテリジェントなものがあります。

それらの利点は、HTMLで動作し、出力がHTMLコードの文字列ではなく、データが挿入されたDOMツリーであることを既に「知っている」ことです。 同時に、そのようなテンプレートエンジンの入力に送られた各データ要素は、対応するDOMノードに関連付けられます。 したがって、コレクションの要素を変更すると、この要素が関連付けられているノードのみが更新されます。 たとえば、100個の要素のリストを返します。 スマートテンプレートエンジンの場合、コレクションのどの要素のコンテンツが変更されたかを判断し、ビュー全体を再描画することなく、対応するノードのみを更新します。

このアプローチは、特に大きなデータセットの場合、間違いなくより効果的です。

しかし、繰り返しますが、それでも主要な問題-データの操作-は解決しません。

はい、パイプフィルタを使用する機能はこのようなテンプレートエンジンに組み込まれているため、出力前にデータを変更できますが、まず、このアプローチではテンプレートの可読性が低下します。 第二に、これはテンプレートエンジンの可能性であり、テンプレートエンジンを使用するフレームワークではなく、より複雑な状況では、テンプレート側とコントローラー/コンポーネント側の両方でコードが蓄積することはありません。

その結果、ここで複数回言及されている基本的な問題、つまりデータ処理が発生します。



base.jsについて



Basis.jsは、データを扱うことを期待して構築されたコアを持つフレームワークです。

このフレームワークの特徴は、アプリケーション構築モデル自体です。

base.js上の完全なアプリケーションは、データストリームが循環しているコンポーネントの階層です。

同時に、base.jsでのアプリケーションの作成はアプリケーションの部分間のリンクの確立であるため、データストリームのイメージは何が起こっているかの本質を最もよく反映しています。

適切に構築されたアプリケーションは、DOM要素の些細な列挙さえも不要にします。

フレームワーク自体とその柔軟なツールは、すべてに責任があります。

同時に、フレームワーク自体は抽象化に基づいて構築されているため、ポリモーフィズムの利点を活用でき、ほとんどの場合、特定の実装から抽象化できます。



フレームワークの作者によって書かれたこの記事で 、basis.jsの操作の基本を学ぶことができます。

一連の記事を続ける機会がありました。



理論から実践へ



SPAの主要なコンポーネントの1つは、ユーザーのアクションに対するアプリケーションの応答、つまりデータのタイムリーな更新です。

データについて話している場合、basis.jsには、データを記述するための多くの抽象化があります。

これらの中で最も単純なのは、 Tokenクラスです。

トークンを使用すると、変更にサブスクライブできるスカラー値を記述できます。

let token = new basis.Token(); //  Token let fn = (value) => console.log('  :', value); // – token.attach(fn); //     token.set(''); //    // console>   :  token.set('habrahabr'); // console>   : habrahabr token.set('habrahabr'); //     , ..       token.detach(fn); //     token.set('basis.js'); //    ,      
      
      





Token#attach method-トークン値の変更にサブスクライバーを追加します。

トークン#detachメソッド-以前に追加されたサブスクライバーを削除します。



さらに、あるトークンは別のトークンに依存する場合があります。

 let token = new basis.Token(); let sqr = token.as((value) => value * value); //    ,   token let fn = (value) => console.log('  :', value); token.attach(fn); token.set(4); // console>   : 4 console.log(token.get()); // console> 4 console.log(sqr.get()); // console> 16 token.set(8); // console>   : 8 console.log(token.get()); // console> 8 console.log(sqr.get()); // console> 64 token.detach(fn); token.set(10); console.log(token.get()); // console> 10 console.log(sqr.get()); // console> 100
      
      





Token#as-新しいトークンを作成し、元のトークンの値の変更に自動的にサブスクライブします。

元のトークンの値を変更すると、 asで指定された関数に転送さ 、その結果が生成されたトークンに書き込まれます。

したがって、トークンのチェーンを作成できます。各トークンの値は、前のトークンの値に依存します。

 let token = new basis.Token(); let sqr = token.as((value) => value * value); let twoSqr = sqr.as((value) => value * 2); let fn = (value) => console.log('  :', value); token.attach(fn); token.set(4); // console>   : 4 console.log(token.get()); // console> 4 console.log(sqr.get()); // console> 16 console.log(twoSqr.get()); // console> 32 token.detach(fn); token.set(10); console.log(token.get()); // console> 10 console.log(sqr.get()); // console> 100 console.log(twoSqr.get()); // console> 200
      
      





トークンは、 Token#destroyメソッドを呼び出すことで破棄できます。

破壊されたトークンは、値の更新についてサブスクライバーに通知するのをやめ、新しいサブスクライバーを追加することができなくなるため、完全に役に立たなくなります。



データを更新するためのこのシンプルで便利なメカニズムは、basis.jsに規定されています。



base.jsのコンポーネントでトークンがどのように使用されるかを見てみましょう。

 let Node = require('basis.ui').Node; let nameToken = new basis.Token(''); new Node({ container: document.body, //    template: resource('./template.tmpl'), //  binding: { name: nameToken }, action: { //   input: (e) => nameToken.set(e.sender.value) } });
      
      





そして、これがテンプレートです:

 <div> <input type="text" event-input="input"> <div> {name}</div> </div>
      
      





これで、テキストフィールドにデータを入力すると、現在の値が{name}に置き換えられます。

言い換えると、 Node#バインディングプロパティは、プロパティがトークンになるオブジェクトです。

ノードは、そのようなトークンの値の変更にサブスクライブし、プレゼンテーションをタイムリーに更新します。実際に変更された部分のみが表示されます。



もちろん、 トークン番号の例は無視できません:

 let Node = require('basis.ui').Node; let nameToken = new basis.Token(''); new Node({ container: document.body, template: resource('./template.tmpl'), binding: { name: nameToken.as(value => value.toUpperCase()) }, action: { input: (e) => nameToken.set(e.sender.value) } });
      
      





すでに何が表示されるか推測しましたか?



もちろん、異議を唱えることもできます:

pppffff ...角度では、同じことはコードの単一行なしでまったく行われます


はい、しかし後で、basis.jsがはるかに複雑なタスクをいかにエレガントに処理するかがわかります。



サイクルのこの部分には実践よりも理論があるという事実にもかかわらず、さらにトピックを理解するのに役立つ、basement.jsの最も重要な側面の1つを調べました。



私のようにES6が好きで、basis.jsと一緒に使用したい場合は、 このプラグインが必要です。



ご清聴ありがとうございました!



貴重なアドバイスをいただいたlahmatiyに感謝します;)



便利なリンク:





UPD:

第二部

base.jsでGitterチャットを開始しました。 追加し、質問します。



All Articles