1.简介
最近在做一个大型网上银行项目前端的优化,需要使用一个胖客户端的优化,大概思路就是前端通过Ajax 请求去后端获取数据,以Jason的格式返回,然后显示在页面上。由于这个系统非常庞大,胖客户端方案难免需要在客户端写大量的JS代码。我想对于任何团队来说,大量的,非结构化的代码维护起来都非常的不方便。所以BackBone进入了我的视线。
它提供了一种途径可以让你结构化你的JS代码,让你以面向对象的方式来组织你的前端JS代码。这就好比我们在前端应用Domain Driven Design. 我们可以把一个非常大的项目按模块切分。 每个模块里面又可以按照BackBone的要求切分成View, Model, Router。
通过backbone,你可以把你的数据当作Models,通过Models你可以创建数据,进行数据验证,销毁或者保存到服务器上。当界面上的操作引起model中属性的变化时,model会触发change的事件;那些用来显示model状态的views会接受到model触发change的消息,进而发出对应的响应,并且重新渲染新的数据到界面。在一个完整的backbone应用中,你不需要写那些胶水代码来从DOM中通过特殊的id来获取节点,或者手工的更新HTML页面,因为在model发生变化时,views会很简单的进行自我更新。
2.特点
Backbone是一个轻量级的前端框架,用于结构化管理页面中的大量JS,建立与服务器、视图间的无缝连接,为构建复杂的应用提供基础框架。
下面我先简单地阐述下Backbone的主要特点及特性:
2.1 轻量级
Backbone的源码只有1000行左右(去注释和空行后),文件大小只有16KB,加上依赖库Underscore,也仅有29KB。
你只需要花一点时间,就能轻松了解Backbone内部实现;或编写少量代码,来重载Backbone的部分机制;如果你想在Backbone的基础上做二次开发,也并不是一件复杂的事情。
2.2 结构化
Backbone可以轻松将页面中的数据、逻辑、视图解耦,依照Backbone进行代码结构组织,你可以将项目中的数据交互、业务逻辑、用户界面等工作,分配给多个同事同时开发,并能有序地组织到一起。同时,这对于大型和复杂项目的维护开发非常有帮助。
2.3 继承机制
在Backbone中,模块是可以被继承的,你可以通过面向对象的方式将应用中的数据模型、集合、视图有序地组织,让整个架构更加清晰;也可以方便地重载和扩展自定义方法。
2.4 建立与服务器的无缝连接
在Backbone中内置了一套与服务器数据的交互规则(如果你了解REST架构,就能够轻松地理解它们),而数据的同步工作会在Model中自动进行,前端开发人员只需对客户端数据的进行操作,Backbone会自动将操作的数据同步到服务器。
这是件非常有趣的事情,因为服务器数据接口对前端开发者来说是透明的,他们不需要再关心如何和服务器交互。
然而服务器提供的数据接口也需要兼容Backbone的规则,对于一个新的项目来说,我们可以尝试使用这套规则来构建接口。但如果你的项目中已经有一套稳定的接口,你可能会担心接口改造的风险。
没关系,我们可以通过重载Backbone.sync方法来适配现有的数据接口,针对不同的客户端环境,我们还可以实现不同的数据交互方式。例如:用户通过PC浏览器使用服务时,数据会实时同步到服务器;而用户通过移动终端使用服务时,考虑到网络环境问题,我们可以先将数据同步到本地数据库,在合适的时候再同步到服务器。而这些只需要你重载一个方法就可以实现。
2.5 界面事件管理
在MVC中,我们希望能将界面展现和业务逻辑完全分离,但对于用户产生的交互事件(如单击事件),我们却常常通过类似jQuery中的bind方法进行获取和绑定。
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
Bitte versuchen Sie es erneut, indem Sie mit den Schaltflächen „Zurück“ und „Vorwärts“ des Browsers zwischen den soeben eingegebenen Adressen hin und her wechseln.
Sie können sehen, dass die gebundene Methode ausgeführt wird, wenn sich der URL-Hash ändert. Wenn ein undefinierter Hash auftritt, wird die showError-Methode ausgeführt und der undefinierte Hash an diese Methode übergeben.
Backbone zeichnet Adressänderungen standardmäßig über Hash auf. Bei Browsern niedrigerer Versionen, die onhashchange nicht unterstützen, werden Hash-Änderungen über setInterval Heartbeat überwacht, sodass Sie sich keine Sorgen über Browserkompatibilitätsprobleme machen müssen.
Für Browser, die die HTML5-PushState-Funktion unterstützen, ermöglicht Backbone auch die Erstellung personalisierter URLs über PushState, dies erfordert jedoch einige Anpassungen auf Ihrem Webserver.
3. Anwendbarkeit von Backbone
Backbone ist nicht so anpassungsfähig wie jQuery. Wenn Sie die Erstellung einer großen oder komplexen einseitigen Webanwendung vorbereiten, ist Backbone perfekt.
Wenn Sie Backbone auf Ihre Website-Seite anwenden möchten und die Seite keine komplexe Logik und Struktur aufweist, wird Ihre Seite dadurch nur umständlicher und schwieriger zu warten.
Wenn Ihr Projekt nicht komplex ist, Ihnen aber eine bestimmte Funktion davon wirklich gefällt (vielleicht das Datenmodell, die Ansichtsverwaltung oder der Router), können Sie diesen Teil des Quellcodes aus Backbone extrahieren, da in Backbone jeweils die Abhängigkeiten zwischen Module sind nicht sehr stark und Sie können eines der Module problemlos erwerben und verwenden.
4. Abhängige Bibliotheken
Sie können Backbone nicht unabhängig verwenden, da seine Grundfunktionen, DOM-Operationen und AJAX alle auf Bibliotheken von Drittanbietern basieren.
4.1 Unterstrich
(erforderlich)
Underscore ist eine grundlegende Funktionsbibliothek zur Verbesserung der Entwicklungseffizienz. Sie kapselt allgemeine Vorgänge für Sammlungen, Arrays, Objekte und Funktionen. Genauso wie jQuery DOM-Objekte kapselt, können Sie über Underscore problemlos auf JavaScript-interne Objekte zugreifen und diese bedienen.
Underscore bietet auch einige sehr praktische Funktionsmethoden, wie z. B. Funktionsdrosselung, Vorlagenanalyse usw.
Einige der Hauptmethoden in Underscore werde ich im nächsten Kapitel ausführlich vorstellen, aber vorher müssen Sie verstehen: Underscore ist eine Bibliothek, auf die sich Backbone verlassen muss, da viele Implementierungen in Backbone auf Underscore basieren.
4.2 jQuery und Zepto
(optional)
Ich glaube, Sie kennen jQuery. Es handelt sich um ein browserübergreifendes DOM- und AJAX-Framework.
Für Zepto kann man es sich als die „mobile Version von jQuery“ vorstellen, da es kleiner, schneller und besser für die Ausführung im Browser mobiler Endgeräte geeignet ist. Es hat die gleiche Syntax wie jQuery, sodass Sie es wie folgt verwenden können jQuery.
Zepto unterstützt derzeit nur Webkit-basierte Browser und ist daher mit den meisten mobilen Systemen wie iOS, Adnroid, Symbian, Blackberry und Meego kompatibel. Windows Phone oder Firefox OS werden jedoch noch nicht unterstützt.
Da jQuery und Zepto die gleiche Syntax haben, gibt es für Backbone kein Problem, ob Sie jQuery oder Zepto verwenden (natürlich können Sie nicht beide gleichzeitig verwenden).
In Backbone verwenden DOM-Selektoren, DOM-Ereignisse und AJAX alle jQuery-Methoden. Der Grund dafür, dass sie hier optional sind, besteht darin, dass Sie sie nicht importieren müssen, wenn Sie die Ansichten und AJAX-Datensynchronisierungsfunktionen in Backbone nicht verwenden.
Wenn Sie nicht jQuery oder Zepto verwenden möchten, sondern eine andere oder benutzerdefinierte Bibliothek verwenden möchten, ist dies kein Problem, solange Ihre Bibliothek dieselben DOM-Selektoren, Ereignisverwaltung und AJAX-Methoden wie die jQuery-Syntax implementiert.
Mit Backbone können Sie die Bibliotheken von Drittanbietern, die Sie verwenden müssen, dynamisch über die setDomLibrary-Methode konfigurieren. Diese Situation wird häufig verwendet:
Obwohl Ihre benutzerdefinierte Bibliothek Methoden mit derselben Syntax wie jQuery enthält, sind die globalen Variablen nicht $ und Sie möchten die vorhandene Benennung beibehalten. Zu diesem Zeitpunkt können Sie es über die setDomLibrary-Methode auf das Objekt festlegen, auf das Backbone intern verweist.
Sie möchten entscheiden, welche Bibliothek besser geeignet ist, indem Sie die Umgebung des Benutzers untersuchen. Zum Beispiel: Wenn der Benutzer über einen PC-Browser zugreift, wird jQuery geladen; wenn der Benutzer über ein mobiles Endgerät zugreift, wird Zepto geladen.