まえがき
この投稿の目的は、Jiant Webフレームワークを普及させ、そのプロモーションに参加したい人を見つけ、フレームワークのさらなる開発と配布のためのコミュニティを作成することです。 JiantはJQueryを積極的に使用し、自然にJQueryと対話し、複雑なWebアプリケーションを整理および簡素化するという目標を達成します。
対象読者-Web開発者にとって有用であると思いますが、特にJavaなどのサーバーから来た人にとっては有用だと思います。
githubへのリンク: https : //github.com/vecnas/jiant
todo-mvcへのリンク: https : //github.com/vecnas/todo-mvc
はじめに
Jiantは、開発を簡素化および高速化し、JavaScriptアプリケーションをサポートするためのツールセットを提供するWebアプリケーション開発フレームワークです。
jiantアプリケーションはJavaScript変数として宣言され、いくつかのセクションが含まれています。 これらのセクションの1つはモデルです。 このセクションでは、アプリケーションデータモデルを宣言します。
var app = { models: { user: { //declaration is here }, env: { //declaration is here } } }
各モデルについて、そのフィールドは最小限の形式で記述され、Jiantは自動的にモデルを実装します。 モデルには、シングルトン(アプリケーション内の唯一のデータオブジェクト)とリポジトリ(オブジェクトのコレクション)の2種類があります。
現在知られているすべてのフレームワークに対する利点は、最小限のコード、IDEでの自動補完の利便性、自動ドキュメント化、理解の容易さ、アプリケーションの最も単純な部分への自然な分解です。
シングルトンモデル
宣言には、フィールドのリストと、update、on、offなどのデフォルトで追加されるいくつかの関数が含まれます。
models: { loggedUser: { // auto-added function, declared for readability update: function(obj) {}, // model fields firstName: function(val) {}, lastName: function(val) {}, id: function(val) {} } }
または:
app.models.loggedUser = { // auto-added function, declared for readability update: function(obj) {}, // model fields firstName: function(val) {}, lastName: function(val) {}, id: function(val) {} }
フィールドは、更新などのいくつかの事前定義されたものを除き、すべて空の関数です。 実装は、次の関数が呼び出されたときにJiantによって実行されます。この時点で、すべてのモデルをアプリケーション記述ファイルに追加する必要があります。
jiant.bindUi(app);
モデルのプロパティを変更する
バインド後、通常はjiant.onUiBoundメソッド内でモデルを使用できます。
jiant.onUiBound(app, function($, app) { var loggedUser = app.models.loggedUser; loggedUser.firstName("Joy"); })
json形式のデータがある場合、単純にupdateを呼び出すことができます(最も一般的に使用されるスクリプトは、サーバーからデータを受信することです)。
var userData = { firstName: "John", lastName: "Smith", id: 1234 }; app.models.loggedUser.update(userData);
便利は何ですか? これで、最初のブロックに関連付けられていないコード内のどこからでも、たとえばどこからでもこのデータにアクセスできます。
var loggedUserId = app.models.loggedUser.id();
setterとgetterの構文は同じであり、モデル自体が何を呼び出しているかを決定していることに気付くことができます。
loggedUser.firstName() // getter loggedUser.firstName("Johann") // setter loggedUser.firstName(undefined) // setter
合成法
モデル内では、setter / getterよりも複雑な機能を提供するメソッドを定義できます。
loggedUser: { //... fullName: function() { return this.firstName() + " " + this.lastName() } }
別のモデルへのリンクを返すか、誰かがログインしているかどうかだけを伝えることができます。
models: { env: { loggedUser: function() {return app.models.loggedUser} isLogged: function() {return !!app.models.loggedUser.id()} } }
合成メソッドでは、変更通知は生成されません(on、off、asapメソッドはありません)。
サブスクリプションを変更
モデルの各プロパティは、このプロパティの変更にサブスクライブするための.on(コールバック)メソッドを提供します。
jiant.onUiBound(app, function($, app) { app.models.loggedUser.id.on(function(loggedUser, id) { alert("logged user id changed: " + id); } })
onメソッドの完全なコールバック構文:
function(modelObject, newValue, oldValue)
offメソッドが含まれています。 また、モデルオブジェクト自体については、同じonメソッドを使用してフィールドを変更するためのサブスクリプションを利用できます。
app.models.loggedUser.on(function(loggedUser) {})
できるだけ早く
特定のデータが利用可能な場合、または既に利用可能な場合はすぐにコードを実行する必要がある場合がよくあります。 この場合、asap(できるだけ早く)メソッドが使用されます。これは1回のみ-すぐに、または必要な値が表示されたときに機能します。
app.models.loggedUser.id.asap(function(loggedUser, id) { alert("Hello " + loggedUser.fullName()); })
リポジトリモデル
リポジトリの主な違いは、リポジトリではなく、このモデルの多くのオブジェクトを格納することです。 したがって、リポジトリを使用した作業はコレクションとして実行されます。 名前リポジトリは、Java SpringフレームワークのJpaRepositoryに基づいてアイデアが最初に生まれたために使用されます。 同時に、宣言の構文はシングルトンに似ていますが、コレクションを操作するためのメソッドが追加されています。
models: { listing: { updateAll: function(arr, removeMissing) {}, add: function(arr) {}, remove: function(obj) {}, all: function() {}, findById: function(val) {}, listByTp: function(val) {}, id: function(val) {}, tp: function(val) {}, price: function(val) {}, baths: function(val) {}, ui: function(val) {} } }
リポジトリの変更
add、removeメソッドは、その名前が示すとおりに機能します。 唯一の非自明なメソッドはupdateAllです。渡された配列またはオブジェクトのidフィールドとリポジトリの現在のコンテンツを比較し、その後、コンテンツを追加、削除、更新します。 オブジェクトに識別子がない場合は、合成id()メソッドを宣言するか、3番目のパラメーターをupdateAllメソッド(2つのオブジェクトを比較してtrue / falseを返す関数)に渡すことができます。
removeメソッドは任意の方法で使用できます。たとえば、このコレクションobjのオブジェクトがある場合、次の両方の行は同じことを行います。
app.models.listing.remove(obj); obj.remove()
リポジトリの場合、更新メソッドはリポジトリ全体ではなく、単一のオブジェクトに適用されます。
var obj = app.models.listing.findById(365); obj.update(newJsonData); // obj.price(newPrice);
リポジトリオブジェクトの取得
allメソッドはすべてのリポジトリオブジェクトを返し、常に使用可能です。 検索メソッドfindByXXX、listByXXXを定義することもできます。これらは、フィールド(または複数)の値によってリポジトリで検索されます。
findByTp: function(val) {} // tp listByTpAndBaths: function(tp, baths) {} //
フィールドのリストは、複数ある場合、単語Andで分割されます。 これらのメソッドの実装は自動です。 他のフィールドで検索する必要があるとします-空の関数を追加すれば完了です。
findとlistの違いは、findは1つのオブジェクト(最初に見つかったオブジェクト、またはゼロ)のみを返し、listは常に(オブジェクトのリストまたは空の)配列を返すことです。
コレクション機能
allメソッドとlistByメソッドは常に配列を返しますが、配列は単純ではありませんが、ゲッター、更新、削除などの基本モデルのメソッドで強化されています。 例:
app.models.listing.listByTp("obsolete").remove() // tp=="obsolete" app.models.listing.all().price("n/a") // n/a app.models.listing.all().ui() // ui app.models.listing.all().asMap() // json
データだけでなく
モデルには、データだけでなく、任意のオブジェクトを格納できます。たとえば、上記の例では、uiフィールドがあります。そこには、インターフェイスのリストの視覚的表現、jQueryオブジェクトへのリンクが格納され、いつでも適切な場所にアクセスできます
app.models.listing.findById(234).ui().addClass("active")
例
上記の関数の使用例は次のとおりです。
asap-Googleマップはプロジェクトで使用されていたため、初期化時にマーカーを設定する必要がありました。 すべてのコードを1か所に押し込まないために、gmapフィールドがenvモデルに追加され、設定時にマーカー配置コードが機能し始めました。 その結果、1つの混乱ではなく、2つの小さな独立したコードセクションが作成されます。
シングルトン-環境(Googleマップと同じ例、類推は簡単に追加できます)またはログインしたユーザーに関する情報を操作するために常に使用されます
リポジトリ-サーバーからダウンロードされ、インターフェイスに表示されるか、プログラムロジックで使用されるデータリスト。 たとえば、コードで検索し、インターフェースにフルネームを表示する機能を持つ州のリスト:
models: { state: { updateAll: function(arr) {}, findByShort: function(val) {}, short: function(val) {}, full: function(val) {} } }
それから:
var fullStateName = app.models.state.findByShort(short).full()
別の例は、通知と通知です。 着信通知は、単にモデルに組み込まれます。 個別に存在する独立したコードがこのモデルの上にハングアップし、ユーザーに通知を表示し、ユーザーが削除したものを削除します。
さらに少ないコード
発表中
var f = function(val) {}
コードの量を減らすことができます:
models: { state: { updateAll: function(arr) {}, findByShort: f, short: f, full: f } }
これをしないでください、これが関数であるというIDEからの手掛かりはありません(プラグインを開発するまで)。
データを取得しながらソートすることにより、モデルへのアクセスを拡大することができます。 奇妙なことに、1ダースのプロジェクトではこれは必要ありませんでした。 原則として、ソートはサーバー上ですでに実行されているか、追加機能によって実行されます。その説明はこの記事の範囲外です。
ボーナス
理由もなくドキュメント。 モデルを発表すると、すぐにアプリケーションのドキュメントを取得します。
開発をスピードアップします。 少ない書き込み。
大幅に簡素化されたサポート。 アプリケーションは、任意の小さな部分に分割されます。 IDEのオートコンプリートと「場所」の検索は、JavaScriptコードでは非常にまれです。
主な欠点-過度の単純さ-は、最初は「どのように機能するのか、それから単なる空の機能」が明確ではなかったということでした。 修辞的な質問は、これが欠陥であるかどうかです。