1. はじめに
最近、私は大規模なオンライン バンキング プロジェクトのフロントエンドの最適化を行っています。これには、シック クライアントの使用が必要です。一般的な考え方は、フロントエンドが Ajax 経由でデータをバックエンドに要求し、それを返すというものです。 Jason 形式で変換し、ページに表示します。このシステムは非常に大規模であるため、シック クライアント ソリューションでは必然的にクライアント側で大量の JS コードを記述する必要があります。どのチームにとっても、大量の非構造化コードを維持するのは非常に不便だと思います。そこでBackBoneが目に留まりました。
これは、JS コードを構造化し、フロントエンド JS コードをオブジェクト指向の方法で編成する方法を提供します。これは、ドメイン駆動設計をフロントエンドに適用するようなもので、非常に大規模なプロジェクトをモジュールに分割できます。 各モジュールは、BackBone の要件に応じて View、Model、Router に分割できます。
バックボーンを介して、データをモデルとして扱うことができ、モデルを介して、データの作成、データ検証の実行、破棄またはサーバーへの保存が可能になります。インターフェイス上の操作によってモデル内の属性が変更されると、モデルは変更イベントをトリガーし、モデルのステータスを表示するために使用されるビューは、モデルによってトリガーされた変更メッセージを受信し、対応する応答を発行して、新しいデータをインターフェースに接続します。完全なバックボーン アプリケーションでは、モデルが変更されたときにビュー自体が更新されるだけなので、特別な ID によって DOM からノードを取得するためのグルー コードを作成したり、HTML ページを手動で更新したりする必要はありません。
2. 特徴
Backbone は、ページ内の大量の JS を構造的に管理し、サーバーやビューとのシームレスな接続を確立し、複雑なアプリケーションを構築するための基本フレームワークを提供するために使用される軽量のフロントエンド フレームワークです。
Backbone の主な機能と特徴を簡単に説明します。
2.1 軽量
Backbone のソースコードはわずか 1,000 行(コメントと空行を削除した後)で、ファイルサイズは依存ライブラリ Underscore を含めてもわずか 16KB です。
Backbone の内部実装を簡単に理解するには、少しの時間を費やすだけで済みます。また、Backbone に基づいて二次開発を行う場合は、少量のコードを作成するだけで済みます。
2.2 構造
Backbone は、ページ内のデータ、ロジック、ビューを簡単に分離し、Backbone に従ってコード構造を整理することができ、プロジェクト内のデータ操作、ビジネス ロジック、ユーザー インターフェイスなどの作業を複数の同僚に割り当てることができます。同時に開発を順序立てて行うことができます。同時に、これは大規模で複雑なプロジェクトのメンテナンスと開発に非常に役立ちます。
2.3 継承メカニズム
Backbone では、アプリケーション内のデータ モデル、コレクション、ビューをオブジェクト指向で整理して、アーキテクチャ全体を明確にすることができ、カスタム メソッドを簡単にオーバーロードしたり拡張したりすることもできます。
2.4 サーバーとのシームレスな接続を確立する
バックボーンにはサーバー データとの一連の対話ルールが組み込まれており (REST アーキテクチャを理解していれば簡単に理解できます)、データ同期作業はモデル内で自動的に実行され、フロントエンド開発者のみが実行します。クライアントデータに対して操作を実行すると、Backbone は操作したデータをサーバーに自動的に同期します。
これは非常に興味深いことです。なぜなら、サーバー データ インターフェイスはフロントエンド開発者にとって透過的であり、サーバーとの対話方法について心配する必要がなくなるからです。
ただし、サーバーが提供するデータ インターフェイスも Backbone のルールと互換性がある必要があります。新しいプロジェクトの場合は、この一連のルールを使用してインターフェイスを構築することができます。ただし、プロジェクトに安定したインターフェイスのセットがすでにある場合は、インターフェイスの変更のリスクが心配になるかもしれません。
問題はありません。Backbone.sync メソッドをオーバーロードすることで、既存のデータ インターフェイスに適応させることができ、さまざまなクライアント環境に応じてさまざまなデータ対話メソッドを実装することもできます。例えば、ユーザーがPCブラウザ経由でサービスを利用する場合、データはリアルタイムでサーバーに同期され、ユーザーがモバイル端末経由でサービスを利用する場合は、ネットワーク環境の問題を考慮して、まずローカルデータベースにデータを同期することができます。その後、適切なタイミングでサーバーと同期します。これらは、メソッドをオーバーロードするだけで実現できます。
2.5 インターフェースイベント管理
MVC では、インターフェイスのプレゼンテーションとビジネス ロジックを完全に分離したいと考えていますが、ユーザーが生成したインタラクティブ イベント (クリック イベントなど) については、jQuery のバインド メソッドを通じて取得してバインドすることがよくあります。
Backbone のビューは、ユーザー イベントと実行メソッドを順序立てて整理するのに役立ちます。これには、次のような単純な式を宣言するだけで済みます。
events: { // 单击id为”save”的元素时,执行视图的add方法 'click #save': 'add', 'mousedown .button': 'show', 'mouseover .button': 'hide' }
在表达式中,事件名称可以是任意的DOM事件(如click、mouseover、keypress等),元素可以是jQuery支持的任意选择器(如标签选择器、id选择器、class选择器等)。
视图会自动将表达式中的事件绑定到选择器元素,当元素的事件被触发后,视图会自动调用表达式中绑定的方法。
2.6 轻量级模板解析
模板解析是Underscore中提供的一个方法。为什么我要在介绍Backbone特性时引入Underscore中的方法?因为该方法能帮助我们更好地分离视图结构和逻辑,且Underscore是Backbone必须依赖的库。
模板解析方法能允许我们在HTML结构中混合嵌入JS代码,就像在JSP页面中嵌入Java代码一样:
<ul> <% for(var i = 0; i < len; i++) { %> <li><%=data[i].title%></li> <% } %> </li>
通过模板解析,我们不需要在动态生成HTML结构时拼接字符串,更重要的是,我们可以将视图中的HTML结构独立管理(例如:不同的状态可能会显示不同的HTML结构,我们可以定义多个单独的模板文件,按需加载和渲染即可)。
2.7 自定义事件管理
在Backbone中,你可以使用on或off方法绑定和移除自定义事件。在任何地方,你都可以使用trigger方法触发这些绑定的事件,所有绑定过该事件的方法都会被执行,如:
var model = new Backbone.Model(); // 在model对象中向自定义事件custom绑定两个函数 model.on('custom', function(p1, p2) { // todo }); model.on('custom', function(p1, p2) { // todo }); // 触发custom事件,将调用上面绑定的两个函数 model.trigger('custom', 'value1', 'value2'); // 移除custom事件中绑定的所有方法 model.off('custom'); // 触发custom事件,但不会执行任何函数,已经事件中的函数已经在上一步被移除 model.trigger('custom');
如果你熟悉jQuery,你会发现它们与jQuery中的bind、unbind和trigger方法非常类似。
另外,Backbone支持一个特殊事件”all”,当在一个对象中绑定了名为”all”的事件后,该对象在触发任何事件时,都会同时触发”all”事件中绑定的方法。有时这种方法会非常有用,例如我们可以通过”all”事件监听对象状态的变化。
3.路由器
在单页应用中,我们通过JavaScript来控制界面的切换和展现,并通过AJAX从服务器获取数据。
可能产生的问题是,当用户希望返回到上一步操作时,他可能会习惯性地使用浏览器“返回”和“前进”按钮,而结果却是整个页面都被切换了,因为用户并不知道他正处于同一个页面中。
对于这个问题,我们常常通过Hash(锚点)的方式来记录用户的当前位置,并通过onhashchange事件来监听用户的“前进”和“返回”动作,但我们发现一些低版本的浏览器(例如IE6)并不支持onhashchange事件。
Backbone提供了路由控制功能,通过Backbone提供的路由器,我们能通过一个简单的表达式将路由地址和事件函数绑定在一起,例如:
var CustomRouter = Backbone.Router.extend({ routes : { '' : 'index', // 当URL Hash在根目录时执行index方法:url# 'list' : 'getList', // 当URL Hash在list节点时执行getList方法:url#list 'detail/:id' : 'query', // 当URL Hash在detail节点时执行query方法,并将detail后的数据作为参数传递给query方法:url#list/1001 '*error' : 'showError' // 当URL Hash不匹配以上规则时, 执行error方法 }, index : function() { alert('index'); }, getList : function() { alert('getList'); }, query : function(id) { alert('query id: ' + id); }, showError : function(error) { alert('error hash: ' + error); }, }); var custom = new CustomRouter(); Backbone.history.start();
请尝试将这段代码复制到你的页面中,并依次访问以下地址(其中URL表示你的页面地址):
URL URL#list URL#detail/1001 URL#hash1 URL#hash2
請再試著使用瀏覽器的「返回」和「前進」按鈕來回切換剛剛輸入的位址。
你可以看到,當URL Hash發生變化時,會執行所綁定的方法,當遇到沒有定義的Hash時,都會執行showError方法,並將未定義的Hash傳遞給該方法。
Backbone預設會透過Hash的方式來記錄位址的變化,對於不支援onhashchange的低版本瀏覽器,會透過setInterval心跳監聽Hash的變化,因此你不必擔心瀏覽器的相容性問題。
對於支援HTML5 pushState特性的瀏覽器,Backbone也允許你透過pushState來建立個人化的URL,但這需要你的網頁伺服器做一些適配。
3. Backbone的適用性
Backbone並不像jQuery那樣具有非常強的適用性,如果你正準備建立一個大型或複雜的單頁Web應用,那麼Backbone再適合不過。
如果想要將Backbone應用到你的網站頁面中,且頁面中並沒有複雜的邏輯和結構,那麼這只會讓你的頁面更加繁瑣和難以維護。
如果你的專案並不複雜,但你卻深深喜歡它的某個特性(可能是資料模型、視圖管理或路由器),那麼你可以將這部分原始碼從Backbone中抽取出來,因為在Backbone中,各模組間的依賴並不是很強,你能輕易的取得並使用其中的某一個模組。
4. 依賴函式庫
你不能獨立使用Backbone,因為它的基礎函數、DOM操作、AJAX都依賴第三方函式庫。
4.1 Underscore
(必選)
Underscore是一個用來提高開發效率的基礎函式庫,它封裝了對集合、陣列、物件、函數的常用操作,就像jQuery封裝DOM物件一樣,你能透過Underscore輕易地存取和操作JavaScript內部物件。
Underscore也提供了一些非常實用的函數方法,例如:函數節流、模板解析等。
關於Underscore中一些主要的方法,我會在下一章詳細介紹,但在此之前你必須了解:Underscore是Backbone必須依賴的庫,因為在Backbone中許多實作都是基於Underscore。
4.2 jQuery和Zepto
(可選)
相信你對jQuery一定不會陌生,它是個跨瀏覽器的DOM和AJAX框架。
而對於Zepto你可以理解為“行動版的jQuery”,因為它更小、更快、更適合在行動終端裝置的瀏覽器上運行,它與jQuery語法相同,因此你能像使用jQuery那樣使用它。
Zepto目前僅支援Webkit核心的瀏覽器,因此它能相容於iOS、Adnroid、塞班、黑莓機和Meego等大部分行動系統,而對於Windows Phone或Firefox OS,它暫時還不支援。
因為jQuery和Zepto語法相同,所以對於Backbone來說,你無論是使用jQuery還是Zepto,都沒有問題(當然,你不可能兩個同時都用到)。
在Backbone中,DOM選擇器、DOM事件和AJAX,都使用了jQuery的方法。這裡之所以所它們是可選的,是假設你沒有用到Backbone中的視圖和AJAX資料同步功能,那麼就不需要匯入它們。
如果你不想使用jQuery或Zepto,而是使用其它的、或自訂函式庫,只要你的函式庫中實作了與jQuery語法相同的DOM選擇器、事件管理和AJAX方法,那就不會任何問題。
Backbone允許你透過setDomLibrary方法動態配置所需使用的第三方函式庫,這種情況常用於:
你的自訂函式庫雖然包含了和jQuery相同語法的方法,但全域變數並不是$,而且你想保持現有的命名。這時你可以透過setDomLibrary方法將其設定為Backbone內部引用的物件。
你希望透過檢查使用者的環境,來決定更適合使用哪一個函式庫。例如:如果使用者使用PC瀏覽器訪問,則載入jQuery,如果使用者透過行動終端訪問,則載入Zepto。