Backbone.jsを使用した複雑なインターフェイスの作成

画像

Backbone.jsはRIA JavaScriptアプリケーションを作成するためのフレームワークであり、その作成者はCoffeeScriptの作成者であるJeremy Ashkenasであり、BackboneはDocument Cloudの一部であり、Underscrore.jsによって「所有」されています。 バックボーンは、インターフェイスの作成に役立つ非常に軽量なライブラリです。 それはあなたが慣れ親しんでいるライブラリで動作します。
Backboneは、サイズが4Kb未満のクラスのセットであり、コードの構造を形成し、高品質のMVC Webアプリケーションの作成を支援します。
Backboneは、キーと値のようなストレージと独自のイベントを備えたモデル、豊富なAPIを備えたコレクション、宣言的なイベント処理を備えたビュー(元のビュー)を導入することにより、重いJavaScriptアプリケーションの構造を形成し、これらすべてをRESTful JSONインターフェイスをサポートする1​​つのアプリケーションに結合します。

BackboneはUnderscore.jsなしでは機能しません。 REST APIをサポートし、 Backbone.ViewでDOM要素を操作するには、 json2.jsとjQueryのようなライブラリjQueryまたはZeptoを接続することを強くお勧めします。

この記事ではBackbone.jsの構造を調べ、簡単なTodoアプリケーションを段階的に作成します。

Backboneが提供するレバレッジを以下に示します。

Key-Valueストレージとカスタムイベント


モデルのコンテンツが変更されると、モデルの変更にサブスクライブされたすべてのオブジェクトが通知を受け取り、さらにアクションを実行できます。 たとえば、ビュー(元のビュー)はモデルの変更をリッスンし、モデルがビューの状態を変更する代わりに状態を更新します。 疎結合パターンが使用されます。

列挙関数の豊富なAPI


Backboneには、データを処理するための非常に便利な機能が多数付属しています。 他の言語とは異なり、JavaScriptの配列は「未完成」であり、大量のデータを処理する場合は大きな問題になります。

宣言的なイベントビュー


スパゲッティのようなコードを書いた日々は終わりに近づいています。 どのコールバックがどのオブジェクトに関連付けられているかをプログラムで決定できます。

RESTful JSONインターフェース


サーバーと通信する必要がある場合は、「表示」コードでAJAXリクエストを実行し、必要なものを取得する必要があります。 これはすべて、さまざまなxhrアダプター、WebSockets、およびlocalStorageを使用して部分的に単純化されていますが、より単純にすることができます。 このようなエンティティはいくつかの小さなエンティティに分割する必要があります。Backboneはこれを支援します。
Backboneは、プレゼンテーションからデータを分離する機能を提供します。 データを処理し、サーバーと同期し、ビューがモデルの変更をリッスンしてその状態を変更する(データをHTMLで描画する)モデル
現在発生する可能性のある質問に対する回答をすぐにリストします。

jQueryを置き換えますか?

いや 目標は大きく異なります。 Backboneは高レベルの抽象化で動作しますが、jQueryまたは同様のライブラリはDOMで動作し、イベントを正規化します。

異なるアプリケーションがあります。あるライブラリを知っていれば、別のライブラリを知る必要があるという意味ではありません。 ただし、JavaScript開発者は、両方を効果的に使用する方法を知る必要があります。

なぜ私は彼女を使うべきですか?

ほとんどの場合、インターフェイスコードは、ネストされたコールバック、DOM操作、HTMLテンプレート、またはデータを表すHTMLを生成する関数のダーティセットです。 Backboneは、このカオスを制御する優れたツールを提供します。

どこで使用すればよいですか?

バックボーンは、頑丈なインターフェイスとデータ駆動型アプリケーションの構築に最適です。 たとえば、GMailインターフェース、新しいTwitterまたはその他の関連アプリケーション。 Backboneを使用すると、複雑なアプリケーションを簡単に作成できます。

これを使用すると、JavaScriptが豊富なシンプルなhtmlページを作成できますが、概して、BackboneはWebアプリケーションを作成するように設計されています。

カプチーノやスプラウトコアのように見えますか?

はい、いいえ。 はい。前述のフレームワークと同様、主な目標はWebアプリケーション用の複雑なインターフェイスを作成することです。 それらは、バックボーンが非常に軽いという点で異なり、前述のライブラリのどれもそれと比較できません。
バックボーンは非常に軽量で、4kb未満です。
実際、約4 kbはこれに当てはまりません。Backbone4 kb + Underscore.js 3 kb + jQuery 31 KB = 38 KB

Cappuccinoでは、Objective-Jでコードを記述する必要がありますが、SproutcoreビューはJavaScriptコードで宣言する必要があります。 しかし、これらのアプローチのいずれかを間違っているとは言えませんが、Backboneを使用すると、通常のJavaScriptを記述し、通常のHTMLとCSSを使用します。

Backboneで他のライブラリを使用できますか?

もちろん。 DOM、AJAXラッパーだけでなく、テンプレートとスクリプトローダーにもアクセスできます。 Backboneは非常に疎結合です。これは、Backboneと組み合わせてほとんどすべてのツールを使用できることを意味します。

バックボーンの構築


最初、Backboneはモデル、ビュー、およびコレクションのみで構成されていました。コントローラーは含まれていませんでした。 時間が経つにつれて、コントローラーが追加されました。 バックボーンは現在、4つの主要なクラスで構成されています。
簡単にメインクラスを調べ、この知識に基づいて簡単なアプリケーションを作成します。

モデル

異なるものは、異なるMVCフレームワークのモデルと呼ばれます。 Backboneでは、モデルは個別のエンティティと呼ばれ、最も近い類似物はデータベース内のレコードです。 しかし、厳格なルールはありません。 フレームワークWebサイトから:
モデルは、インタラクティブなデータと、それらを構成するほとんどのロジック(変換、検証、計算されたプロパティ、アクセス権)を含むすべてのJavaScriptアプリケーションの中心です。
モデルは、データセットのプロパティまたは属性を読み書きする方法です。 モデルの例を次に示します。
var Game = Backbone.Model.extend({}); 

少し複雑にしましょう:
 var Game = Backbone.Model.extend({ initialize: function(){ alert("Oh hey! "); }, defaults: { name: 'Default title', releaseDate: 2011, } }); 

オブジェクトが作成されると、initializeメソッドが実行されます。 この方法では、有用なことは何もしていません。 一部のデータが転送されない場合に備えて、いくつかのデフォルト変数も定義します。

属性を読み書きする方法を見てみましょう。 ただし、最初にオブジェクトを作成します。
 //    var portal = new Game({ name: "Portal 2", releaseDate: 2011}); //     releaseDate var release = portal.get('releaseDate'); // 2011 //    portal.set({ name: "Portal 2 by Valve"}); 

属性(object.attribute)を直接操作することはできません。データを変更または取得するにはメソッドを呼び出す必要があります(状況はProxyの出現により変わると思います)。
これで、すべてのデータがアプリケーションメモリに格納されました。 それらをサーバーに保存しましょう:
 portal.save(); 

もっと期待した? AJAX? 1行で、サーバーにリクエストを送信します。 リクエストのタイプが変わることに注意してください。新しいオブジェクトを作成すると、POSTリクエストが送信され、そうでない場合はPUTが送信されます。
モデルについて簡単に触れました。 Backboneは、モデルを操作するための非常に多くのオプションを提供します。 詳細はドキュメントに記載されています。

コレクション

Backboneのコレクションは、単なるモデルのコレクションです。 コレクションデータベースと同様に、これらは文字列(モデル)を含むデータベースクエリの結果です。
ゲームのコレクションを作成しましょう:
 var GamesCollection = Backbone.Collection.extend({ model : Game }); 

最初に気づくのは、コレクションがどのモデルで構成されているかを判断することです。 ゲームモデルで構成されるゲームのコレクションを作成しました。

これで、データを操作できます。 たとえば、古いゲームを定義するメソッドを追加して、コレクションを拡張しましょう。
 var GamesCollection = Backbone.Collection.extend({ model : Game, old : function() { return this.filter(function(game) { return game.get('releaseDate') < 2009; }); } }); 

シンプルでしょ? 2009年以前に作成されたこれらのゲームをチェックし、それらを返します。 コレクションを直接管理することもできます。
 var games = new GamesCollection games.get(0); 

上記の例は、新しいコレクションを作成し、ID 0のモデルを取得します。オブジェクトの位置へのリンクを介して、特定の位置の要素を見つけることができますgames.at(0);

最後に、次のようにコレクションを動的に補充できます。
 var GamesCollection = Backbone.Collection.extend({ model : Game, url: '/games' }); var games = new GamesCollection games.fetch(); 


データを管理するURLの助けを借りてBackboneに通知します。 次に、単純に新しいオブジェクトを作成し、 fetchメソッドを呼び出します。これにより、サーバーからのデータの非同期要求が発生し、コレクションに値が設定されます。

これで、Backboneコレクションの基本がわかりました。 上で述べたように、たとえば、Underscoreライブラリのすべてのメソッドなど、Backboneでできる便利な機能がまだたくさんあります。 実験する前にドキュメントを読んでください。

表示する

一見すると、ビューは混乱しているように見えるかもしれません。 純粋なMVCとは異なり、Backboneのビューにはコントローラー機能の一部があります。

種の責任は次のとおりです。
簡単なビューを作成しましょう:
 var GameView = Backbone.View.extend({ tagName: "div", className: "game", render: function() { //    } }); 

すべてが非常に簡単です。 ビュー(tagNameとclassName)のラップに使用するHTML要素を決定するだけです。

次のコードはビューをレンダリングします。
  render : function() { this.el.innerHTML = this.model.get('name'); //   jQuery: $(this.el).html(this.model.get('name')); } 

elは、このビューを表すDOM要素を指します。 単にHTML要素にゲームの名前を入れます。 明らかに、jQueryの使用はもう少し簡単です。

より複雑なマークアップでは、JavaScript内でHTMLコードを使用するのは面倒で無意味です。 これらの場合、パターンを使用する価値があります。

Backboneには独自のテンプレートエンジン(Underscore.JSの一部)がありますが、任意の種類のテンプレートを自由に使用できます。

最後に、種がイベントをリッスンする方法を見てみましょう。 最初のDOMイベント。
 events: { 'click .name': 'handleClick' }, handleClick: function(){ alert('In the name of science... you monster'); // Other actions as necessary } 

もちろん、jQueryほど馴染みがなく、シンプルでもあります。 Eventsオブジェクトを介してリッスンするイベントを決定します。 上記のコードからわかるように、最初の部分はイベントを参照し、次の部分はイベントに関連付けられている関数を定義します。

次に、ビューをモデルに接続します。
 var GameView = Backbone.View.extend({ initialize: function (args) { _.bindAll(this, 'changeName'); this.model.bind('change:name', this.changeName); } }); 

最初に注意することは、バインディングコードを初期化関数に配置する方法です。 初期化はイベントをバインドするのに最適な場所だと思います。

bindAllは、このコンテキストを関数にバインドするアン​​ダースコアメソッドです。 これは、イベントで特に役立ちます。

これで、モデル名が変更されるとすぐに、changeName関数がchangeNameます。 change:代わりに他のプレフィックスを使用して、モデルの状態を照会できます。

コントローラー

コントローラーを使用すると、ハッシュURL(hashbangs)の状態を記憶するアプリケーションを作成できます。
 var Hashbangs = Backbone.Controller.extend({ routes: { "!/": "root", "!/games": "games", }, root: function() { //      }, games: function() { //      } }); 

これは、従来のサーバーMVCフレームワークのルートに非常に似ています。 たとえば!/gamesは関数に関連付けられ、ブラウザのURLはdomain/#!/gamesます。

hashbangsを使用すると 、その状態を記憶し、Googleがインデックスを作成できるWebアプリケーションを作成できます。

これにより[戻る]ボタンが壊れるのではないかと心配している場合は、Backboneが処理します。
 //   var ApplicationController = new Controller; Backbone.history.start(); 

バックボーンは#hashの変更を監視し、コントローラーに通知します。

Backboneの基本を理解したので、テストアプリケーションを作成してみましょう。

例:Todoリスト


このアプリはJérômeGravel-Niquetによって作成されました 。 単純なlocalStorageアダプターを使用して、ブラウザーにデータを保存します(アダプターで停止するのではなく、コードを見てください。すべてが非常に単純です)。 コードの理解を深めるために最後に何が起こるかを見てください: Todo List

Tuduモデル

基本モデルは、 contentorderおよびdone属性を持つリストtodo要素を記述します。
  window.Todo = Backbone.Model.extend({ //     ,    //    ,       default EMPTY: "empty todo...", //     `content`,    initialize: function() { if (!this.get("content")) { this.set({"content": this.EMPTY}); } }, //   `done` toggle: function() { this.save({done: !this.get("done")}); }, //   localStorage    clear: function() { this.destroy(); this.view.remove(); } }); 


ツドゥーコレクション

tuduコレクションはlocalStorageに保存されます
  window.TodoList = Backbone.Collection.extend({ //       Todo model: Todo, //      "todos"  localStorage localStorage: new Store("todos"), //     ,   done: function() { return this.filter(function(todo){ return todo.get('done'); }); }, //     ,    remaining: function() { return this.without.apply(this, this.done()); }, //     ,          . //      GUID   .      . nextOrder: function() { if (!this.length) return 1; return this.last().get('order') + 1; }, //        comparator: function(todo) { return todo.get('order'); } }); //     window.Todos = new TodoList; 


ビュー-トゥドゥ要素

  // DOM    window.TodoView = Backbone.View.extend({ //    tagName: "li", //   //      template: _.template($('#item-template').html()), //  DOM,     events: { "click .check" : "toggleDone", "dblclick div.todo-content" : "edit", "click span.todo-destroy" : "clear", "keypress .todo-input" : "updateOnEnter" }, // TodoView      . //     ---,     //    . initialize: function() { _.bindAll(this, 'render', 'close'); this.model.bind('change', this.render); this.model.view = this; }, //   render: function() { $(this.el).html(this.template(this.model.toJSON())); this.setContent(); return this; }, //   XSS   `jQuery.text`     setContent: function() { var content = this.model.get('content'); this.$('.todo-content').text(content); this.input = this.$('.todo-input'); this.input.bind('blur', this.close); this.input.val(content); }, //   "done"   toggleDone: function() { this.model.toggle(); }, //      edit: function() { $(this.el).addClass("editing"); this.input.focus(); }, //   ,   close: function() { this.model.save({content: this.input.val()}); $(this.el).removeClass("editing"); }, //   `enter`,    updateOnEnter: function(e) { if (e.keyCode == 13) this.close(); }, //  DOM  remove: function() { $(this.el).remove(); }, //     clear: function() { this.model.clear(); } }); 


ビュー-アプリケーション

これがアプリケーションの基本的なビューです。
  window.AppView = Backbone.View.extend({ //  ,        HTML  el: $("#todoapp"), //    //      statsTemplate: _.template($('#stats-template').html()), //       ,   events: { "keypress #new-todo": "createOnEnter", "keyup #new-todo": "showTooltip", "click .todo-clear a": "clearCompleted" }, //        : //  , , .     ,   //   localStorage initialize: function() { _.bindAll(this, 'addOne', 'addAll', 'render'); this.input = this.$("#new-todo"); Todos.bind('add', this.addOne); Todos.bind('refresh', this.addAll); Todos.bind('all', this.render); Todos.fetch(); }, //   -  .   . render: function() { var done = Todos.done().length; this.$('#todo-stats').html(this.statsTemplate({ total: Todos.length, done: Todos.done().length, remaining: Todos.remaining().length })); }, //   .      `<ul>` addOne: function(todo) { var view = new TodoView({model: todo}); this.$("#todo-list").append(view.render().el); }, //    addAll: function() { Todos.each(this.addOne); }, //      newAttributes: function() { return { content: this.input.val(), order: Todos.nextOrder(), done: false }; }, //   return      -   . //            createOnEnter: function(e) { if (e.keyCode != 13) return; Todos.create(this.newAttributes()); this.input.val(''); }, //    ,   . clearCompleted: function() { _.each(Todos.done(), function(todo){ todo.clear(); }); return false; }, //      . showTooltip: function(e) { var tooltip = this.$(".ui-tooltip-top"); var val = this.input.val(); tooltip.fadeOut(); if (this.tooltipTimeout) clearTimeout(this.tooltipTimeout); if (val == '' || val == this.input.attr('placeholder')) return; var show = function(){ tooltip.show().fadeIn(); }; this.tooltipTimeout = _.delay(show, 1000); } }); //  -    window.App = new AppView; 

注釈付きのオリジナルはここで表示できます。

HTMLテンプレートとCSS

  <!--  --> <div id="todoapp"> <div class="title"> <h1>Todos</h1> </div> <div class="content"> <div id="create-todo"> <input id="new-todo" placeholder="What needs to be done?" type="text" /> <span class="ui-tooltip-top" style="display:none;">Press Enter to save this task</span> </div> <div id="todos"> <ul id="todo-list"></ul> </div> <div id="todo-stats"></div> </div> </div> <!--  --> <script type="text/template" id="item-template"> <div class="todo <%= done ? 'done' : '' %>"> <div class="display"> <input class="check" type="checkbox" <%= done ? 'checked="checked"' : '' %> /> <div class="todo-content"></div> <span class="todo-destroy"></span> </div> <div class="edit"> <input class="todo-input" type="text" value="" /> </div> </div> </script> <!--  --> <script type="text/template" id="stats-template"> <% if (total) { %> <span class="todo-count"> <span class="number"><%= remaining %></span> <span class="word"><%= remaining == 1 ? 'item' : 'items' %></span> left. </span> <% } %> <% if (done) { %> <span class="todo-clear"> <a href="#"> Clear <span class="number-done"><%= done %></span> completed <span class="word-done"><%= done == 1 ? 'item' : 'items' %></span> </a> </span> <% } %> </script> 

CSSは適用しません。 非常に長く 、完全にトピックから外れています。

これでテストアプリケーションの準備が整いまし 。結果はこちらで確認できます

バックボーンから学べること


Backboneアプリケーションアーキテクチャから学べるいくつかのレッスンを次に示します。
少なくとも私にとっては、Backboneがインターフェース作成の概念を変えていると言えば十分です。 ご質問がある場合は、お問い合わせください。

書き込み時に使用されたソース


Backbone.jsを使用してJavaScriptアプリを作成する (Jim Hoskins)
Backbone.jsの開始方法 (Siddharth)
アダプターのバックボーン位置ストレージ
Todosの例 (JérômeGravel Niquet)
注釈付きのTodos.jsソース

他に読むもの


GitHub バックボーンドキュメント
GitHubのアンダースコアドキュメント
ノードチュートリアルパート19:Backbone.js (Alex Young)
大規模なJavaScriptアプリケーションの作成 (オリジナルのAddy Osmani、翻訳trurl123

Source: https://habr.com/ru/post/J118782/


All Articles