利用BackboneJS更好组织jQuery应用的架构(一)
在构建高交互度的Web应用程序方面,JavaScript发挥出越来越重要的作用。如Backbone.js,Marionette.js,Ember.js和Angular.js这些库和框架,在流行度和功能方面快速成长。对于建立复杂和强大的浏览器应用这件事,这些库和框架使之变得容易了。它们帮助我们迎来了一个单页应用时代(SPAs),使网页上的交互性和实用性达到了前所未有的程度。
但为了达到互动的目的,并不是每个Web应用程序或网站上的每个页面都需要通过SPA框架来创建。很多应用程序更适合于小规模的功能。对于这些页面,需要有一种高层次的交互性,同时又不需要客户端路由和其他的SPA功能属性。随着小页面在功能需求方面的减少,在创建页面时,将适当的框架和库的列表减少也顺理成章。例如,如果只是添加表单验证,你并不需要一个完整的MVC框架。要是不需要一个完整的SPA框架,而且有很好的理由的话,许多开发者编写代码时只会用到jQuery。而为了创建进一步的交互动作,可以很容易地通过plug-ins和add-ons扩展jQuery提供的交互性。
在建造大型的jQuery应用时,所面临的困难之一是保持代码有条理。它很容易迷失于世界末日的一棵圣诞树——一个深层嵌套的回调函数列表,这个列表看起来似乎掌控着每一个功能和交互。事实上,对于代码的组织或结构,jQuery不提供任何指导。
好消息是,你不需要在jQuery和结构良好的代码之间做出选择,后者由SPA库和框架帮你书写。借助Backbone.js提供的结构良好的创建模块,你可以把基于jQuery应用的简单性和交互性结合起来,以便创建同样具有很好代码组织结构的高互动性的网页。
什么是Backbone.js
Backbone.js是一个帮助开发者在Web应用程序中向Javascript代码添加架构的组件库。来自BackboneJS.org的描述是这样的:
“Backbone.js通过提供带有键值绑定的模型和定制的事件,带有枚举功能的丰富的集合API,带有声明式事件处理的视图,而且将它所有这些东西通过一个RESTfulJSON接口连接到你现有的API上面,来向Web应用程序提供架构。
Backbone.js包含了提供不同组特定功能集合的构造块,包括:
Model:包含由键值对组成的属性的对象。Model封装了应用程序中的数据以及同数据相关的行为。
Collection:是一个模型的集合。Collection可以让相关模型的集合共同工作并且作为一个整体被管理。通用的集合特性诸如新增和移除,迭代,过滤等都有提供。
View:用于管理和操作DOM的通用方法集合与配置,并且显示来自Model和Collection的数据。View提供了使用jQueryDOM事件的一种结构良好的方法,它们可以很容易的对HTML模板以及更多的其它东西进行渲染。
Event:它是对面向Javascript对象的观察者设计模式的一个小巧但强大的实现。事件将Backbone.js应用粘合在一起。Backbone.js中的每一个对象都包含事件系统,它让每一个Backbone.js对象都能触发事件并能得到处理。
Router和History:使用URL哈希片段或者HTML5的pushState技术来管理浏览器历史的对象集合。Router和History对象允许对一个应用程序的对象打上书签或者链接,重载页面的时候精确的回到上一次最后留下的样子。
尽管Backbone.js有其它小的部分,但如果需要定制它们的时候,理解这些很重要。不过从一个高层次观察,对于大多数应用程序来说,这六个对象是最重要的。
在这些Backbone.js单个部分之外,从模式与架构的视角,有一些关于如何称呼它的争论。显然Backbone.js符合Model-View-*(MV*)模式家族。毕竟它提供了一组对象,帮助你组织模型和视图。但这并不完全符合MVC模式,或MVVM模式,或MVP,或别的什么。称Backbone.js为MV*家族的一个成员是最简单的。在此基础上,人们叫它什么并没有多大差异。
建立联系人列表
许多应用类型需要为他人存储和查询联系人信息,比如一个CRM系统,一个时间追踪应用,账单或者其他的一些东西。尽管联系人应用可能还没有最令人激动的特性集合,但它提供了一个使用高级交互性的很好的例子,但不需要成为SPA。
一个简单的联系人列表仅仅需要少量的特性:
联系人列表
添加联系人
编辑联系人
删除联系人
联系人数据
它也需要与这些特性相配的数据,包括:
姓名
图片URL
邮件地址
电话号码
注释
在学习Backbone.js过程中使用的简单联系人列表仅仅需要处理一个单独的邮件地址和电话号码。在真正的应用中,你会想要允许多个电话号码和邮箱地址,但Backbone.js没有内建的嵌套或者分层的模型。这让处理多值或者嵌套对象和集合变得有些更具挑战性,尽管通过插件添加这项功能并不困难。一个简单的邮件地址和电话号码可以满足这个应用。
这个应用的布局相对简单,可以如图片1和图片2的样子。只需要一个列表视图而且有一个表单来添加和编辑联系人。
Clickforalargerversionofthisimage.
图片1:这是添加联系人表单
Clickforalargerversionofthisimage.
图片2:这是联系人列表例子。
当你点击添加按钮,表单将显现,并允许你添加一个新的联系人。点击保存将联系人信息发送到服务器。点击取消清除表单并隐藏表单。
在联系人列表中,点击编辑按钮可以显示同添加过程一样的样子,但是表单里将有存在的联系人信息。点击保存并发送编辑信息给服务器。保存还是用最新的信息来更新联系人列表。取消将抛弃任何改变并不会更新列表。
一个API服务器
Backbone.js为数据提供一个如REST的API,并能和服务器端很好的交互。这个在很多语言中都能很容易的安装,包括RubyonRails、NodeJS、ASP.NETMVC(包括WebAPI)、PythonDjango和各种PHP框架等等。最重要的方面不是服务器使用的技术架构。当然,其重点是如REST的API并能提供各种资源。
Backbone.js是在Rails的世界中开发的,所以它的API使用起来如一个Rails生成的API。Backbone.js工作使用的每一个资源应该对应一个在Web服务器上的API,这个API可以接受和返回JSON,而且符合RailsURL和HTTP的约定动作。
在某个联系人列表里,其API可能如下:
GET/contacts:返回所有联系人
POST/contacts:从表单数据中创建一个新的联系人,其数据用JSON格式
GET/contacts/:id:通过参数id得到指定联系人
PUT/contacts/:id:通过得到表单传来的JSON格式数据来更新一个存在的联系人。通过id参数来标识更新的联系人
DELETE/contacts/:id:通过指定id来删除联系人
这篇文章中构建联系人应用是一个技术而且对于服务器框架来说是未知的,直到服务器符合了基本API结构。至于你怎样才能实现服务器框架则完全取决于你。
新增表单
在为这个app准备的javascript中首先要做的,是处理新增按钮的点击。添加一个标准的jQueryDOMReady回调函数,以确保DOM已经准备好并且可用了。然后,在DOMReady回调函数里面,添加一个找到#add元素的选择器还有对点击事件的侦听。在事件参数上调用preventDefault以确保按钮的点击不会传到服务器。
$(function(){
$("#add").click(function(e){
e.preventDefault();
showAddForm();
});
//othercodewillgohere...
});
在事件的回调函数里面制造了一个对showAddForm的调用,以展示添加表单。这个函数找到#add-edit-form元素,并且使用动画来展示它。
functionshowAddForm(){
varform=$("#add-edit-form");
form.slideDown();
}
接下来,为#save按钮的点击事件添加一个事件处理器。这个按钮存在于#add-edit-form里面,但它也可以通过ID被选择器找到。在点击处理器中,从表单中所有的输入元素中抓取数据并且将其发送到服务器以创建一个新的contact。当这些都做好以后,就用新的contact信息更新contact的列表,就像列表1所展示的那样。
当向服务的传送成功时,它会调用updateList和clearForm函数,它们会做你所希望做的事情(简洁起见,这些断码从略)。
不需要完成这个简单应用的整个功能,你就能看明白现在代码能够很快的变成一揽子可用的功能挂在上面。这种结构松散的代码被相当典型的用在使用jQuery的小型页面上。几乎每一个Javascript和jQuery开发者都写过类似的代码,而这一风格由于其能让一些小型的任务得以完成,因此会持续流行下去。
编写结构良好的jQuery代码是可能的,当然,即使你使用了提供那种架构的框架或者库也可以。那会变得像是你在重复制造轮子,所以你应该专注于如何让业务运作起来。不要在构建基础架构上花时间,就使用模型,集合,视图和其他Backbone.js能够提供的类型,将你的应用程序迁移到这样一个更好的架构上,然后一步一个脚印。
从jQuery到Backbone.js:迁移
在这一点上直接跳转到Backbone.js上是很有诱惑力的,但那可能会给大多数开发者帮倒忙。从头开始是很容易的。真正的挑战在于处理现有的代码并将其移植到其它的东西上。
迁移到Backbone.js的方式要做两件事:
表明不必用一种全都要或者全都不要的重写来将Backbone.js加入到现有的项目中。
表明使用jQuery自身与使用Backbone.js来构造jQuery这两种方式的相同和不同之处。
使用原生jQuery代码构建的Add表单可以一步一个脚印按部就班的移植到Backone.js。而在那发生之前,你需要在你的项目中配置Backbone.js。
安装Backbone
Backbone.js技术仅有一个依赖包:Underscore.js。Underscore.js如蝙蝠侠身上的腰带:一个不可缺少的工具集合,实用工具,还有一些玩具,这些都可以让JavaScript更容易的工作。同时它也有其它语言的一些特性,有些特性是浏览器中未来JavaScript版本才有的功能。Underscore.js和Backbone.js类似,都是由JeremyAshkenas创建,并由GitHub中的DocumentCloud组织维护。
如果你想要用Backbone.为了实现组织操作DOM和交互的代码,你也需要一个DOM操作库;jQuery是自然(而且最流行)让人想到的一个不错的选择。
最近,Backbone.js支持了JavaScript文档格式JSON。所有的浏览器都很自然的支持JSON格式。如果你需要支持老的或是指定的不支持JSON的浏览器,你需要从DouglasCrockford引用JSON2.js库,这是JSON标准的创建者。
将所有这些下载的文件放入你工程的/js目录下。在HTML中脚本引用如下:
<scriptsrc="/js/json2.js"></script>
<scriptsrc="/js/jquery.js"></script>
<scriptsrc="/js/underscore.js"></script>
<scriptsrc="/js/backbone.js"></script>
注意顺序也很重要。Backbone.js必须在jQuery和Underscore.js之后。如果你这部分不正确,Backbone.js不会正常工作。
一旦在你的工程中拥有Backbone.js需要的文件以及在你的HTML中得到引用,你就可以开始你的奇妙之旅。
Backbone.View与AddForm
Backbone.View是将Backbone.js引入现有应用的最简单的方法。作为它的核心,Backbone.View只不过是用于组织jQuery代码的一些简单的约定。当然它允许的不仅仅是这些,但从组织jQuery代码开始,进行下去会很容易。
几乎Backbone.js中的任何东西,都需要调用基本类型的扩展,而这个基本类型就是你想要处理的类型。如果你熟悉Java,这个方法名听起来会很熟悉,如果你熟悉C#,这就相当于":"与一个基类。Backbone.js中的扩展方法就是继承的实现。
varAddForm=Backbone.View.extend({
//addconfiguration,methodsandbehaviorhere
});
通过从一个基本的backbone.js类型扩展,你可以创建你自己的专有类型,用它做你的应用需要做的事情。在这个案例中,你创建的是一个名为AddForm的新视图类型。它表现并操作#addform的DOM元素,这与之前原生jQuery操作的是相同的表单元素。
在这个视图{和}定义之内,你可以添加你的视图的具体配置,方法,和行为。有许多配置选项和方法,出乎你的利益,Backbone.View可以识别并使用它们。不过,大多数你所写的代码将是自己设计的。
渲染#addform输入字段
添加到Backbone.View的最常见的函数是render函数。基础的Backbone.View内置有这个方法,但它只是返回了视图的实例,并没有做任何别的事情。它实际上是一种无操作方法。因为这个核心方法的存在,任何应用或框架都可以在View实例中,调用render方法。
要想给你的AddForm添加一个render方法,只需声明这个方法,再加上一个":",将方法名字与函数相隔离。这是JavaScript的对象的语法,它也是用来定义backbone.js中类型的语法。
varAddForm=Backbone.View.extend({
render:function(){
varrawTemplate=$("#add-form-template").html();
varcompiledTemplate=_.template(rawTemplate);
varrenderedTemplate=compiledTemplate();
this.$el.html(renderedTemplate);
returnthis;
}
});
这个视图仅仅只有五行代码,但是每一行都很精彩。
第一行将一个DOM元素的HTML内容加载到一个变量rawTemplate。这是一个HTML模板,与服务器端HTML模板意义相同。它是一个HTML标签的集合,带或不带数据和行为的特殊标记,它可用于生成原始HTML。在之后的某个时刻,你会把这个模板添加到HTML网页。
第二行将模板编译进一个JavaScript函数。在这个案例中,Underscore.js被用作模板引擎,因为backbone.js依赖于Underscore.js,所以它在你的应用程序中已经是可用的。调用_template方法,并传入原始HTML模板,这样就将HTML编译进一个函数。这个函数之后就可以从这个模板生成最终的HTML输出。
第三行运行编译的模板,并从模板生成HTML输出。在本案例中,该方法被调用时没有带参数。可是如果模板中需要数据,就可以传入一个JavaScript对象。这个对象属性的名字与值被用来填塞模板,你会在后面看到这一点。
第四行取到渲染后的HTML,并通过视图的$el属性将其放进视图。$el属性是一个jQuery选择对象,代表这个视图实例所管理的DOM元素。每一个视图实例都默认有一个$el属性,它是一个<div>元素(虽然这可以很容易的改变)。当处理视图实例的时候,所有的DOM控制都是通过视图的$el实现的——包括读取数据,写数据到DOM,更新CSS类,动画,以及其它用jQuery可以做的工作。视图对特定的DOM元素及其子元素,是一个有效的行为封装。
这个方法的最后一行返回视图实例。这使得你在渲染视图以后,将方法与属性访问链接到一行之中。
将要渲染的模板
在AddForm的render方法中,用jQuery选择器引用了一个HTML模板。然后#add-form-template的DOM元素内容被取出来送给Underscore.js的template方法。为了让这一切工作,你需要给DOM元素赋以正确的ID和内容。不过你无需让这个DOM元素显示在页面上。你只需要让它作为一个模板以供渲染。这其中有几个方法,最简单的方法可能不太显眼:用一个<script>标签。
给你的HTML页面添加一个<script>标签,将它的ID设为add-form-template。通常情况下,在浏览器看到一个script标签的时候,它会试着将这个标签解释为JavaScript脚本。这不会是你希望的,因为你创建的模板并不包含可执行的脚本。替代的,它包含的是一个HTML模板。为了阻止浏览器执行脚本的尝试,给这个标签增加一个type属性,将它设置为javascript以外的类型,或者任何浏览器可以识别的类型。最常用的type是text/html-template或者类似的一些类型。
<scriptid="add-form-template"type="text/html-template">
</script>
只要将type设置成浏览器不能识别的类型,实际设置成什么并不重要。不过,最佳实践方法是将type设置成某种类型,使得另一个开发人员可以识别出它是一个模板。
使用<script>标签是由于两个原因:
HTML标准还尚未具有一个<template>标签
HTML模板是在视图中隐藏的,但它仍然需要可被获取使用
给template使用script标签的目的在于第二个原因。你需要HTML模板可以被JavaScript代码访问到,但是你不又希望未渲染的模板显示在浏览器的可视区域,让用户能看到它。用一个script标签再加上一个自定义的属性将能满足这两个需求。Script标签永远不会显示给用户,但是赋之以一个ID却可以使他能被jQuery所选择。提供一个type的额外需求,是将script将本用作它用的副作用,但这是一个可以接收(而且并不显著)的代价。
给模板填上标准的HTML标记,这样就可以创建增加一个联系人所需要的输入表单。
<scriptid="add-form-template"type="text/html">
<label>Name:</label>
<inputtype="text"id="name"><br>
<label>PhotoURL:</label>
<inputtype="text"id="url"><br>
<label>Email:</label>
<inputtype="text"id="email"><br>
<label>Phone:</label>
<inputtype="text"id="phone"><br>
<label>Notes:</label>
<inputtype="text"id="notes"><br>
<buttonid="save">Save</button>
</script>
只要模板和AddForm视图同时具备,就可以渲染表单,并将它放到DOM中,这样用户就可以增添图像了。
查看视图
有一个视图定义是很棒的,但是或许它没啥用,除非它完成了实例化,渲染,以及被放到DOM中让用户可以看到内容并与之交互。
就像其它的JavaScript对象,Java,C#,以及其它的语言,Backbone.js对象由new关键字实例化。只要将新对象实例赋给一个命名变量,你就可以根据需要调用视图上的方法,就像这样。
varaddForm=newAddForm();
手上一旦有了一个view实例,你就可以调用它的render方法,将HTML模板渲染到视图自身之中。
addForm.render();
如果回头看看render方法最后一行代码,你会想起来这个方法并没有返回HTML。而且,它返回的是视图本身。渲染的HTML被放在视图的$el中,也就是视图管理的DOM元素。这个属性可以在view实例上直接获得,而且它也是你用来将视图的HTML加到DOM的工具。
原文:http://www.linuxeden.com/html/news/20131112/145443.html