内容
如果您希望快速构建一个小的JavaScript工具,则可能不打算使用框架。相比于安装和学习新框架,更容易将一些jQuery代码一起黑客攻击,对吧?错误的Backbone.js是一个超轻量级的胶粘框架,看起来就像您用来编写的常规旧JavaScript一样。
我们在ZURB上做了很多静态原型,因为我们希望能够点击页面而无需编写任何后端代码。通常,我们会放下单调的灰色占位符图像,或者有时我们会在Flickr中搜索示例图像,以帮助我们可视化最终草案中可能出现的内容。直到一个神奇的星期五,当我们决定编写一些JavaScript解决我们的问题真是太棒了。我们希望能够直接从占位符图像本身搜索并选择Flickr上的照片。我们将其称为FlickrBomb,这是我们如何使用Backbone.js构建它的故事。
强烈建议您在阅读前快速浏览FlickrBomb。这是“一次点击价值一千个单词”这类交易中的一种。继续,我们将等待。
这些天来有很多JavaScript框架,包括SproutCore,JavaScriptMVC,Spine,Sammy,Knockout。但是出于某些不同的原因,我们喜欢这个特定项目的Backbone.js:
1.轻巧(实际上100%无脂肪)
- 重量,最新的压缩版本约为4.6kb
- 在代码中,只有1000行以上的代码,在不失去头脑的情况下跟踪堆栈跟踪到内部并不难
2.看起来像JavaScript
- 因为它是JavaScript,仅此而已
- 它使用jQuery,这甚至连您的祖母都知道
3.超级简单的持久性
- 开箱即用,它将数据持久化到后端(通过REST),但是通过插入单个插件,它将保存到本地存储中
- 因为它抽象了持久性API,所以我们只需删除本地存储插件就可以将其持久化到REST后端
让我们开始吧
因为Backbone.js只是JavaScript,所以我们要做的就是将其与Underscore.js一起包含在页面上。 jQuery本身并不是Backbone的硬性依赖,但是我们将使用它,因此我们将其包含在这里。我们也将链接本地存储插件,因为我们不想麻烦地设置后端。请注意,为简单起见,这里直接链接文件,但是您应该始终在生产中托管自己的资产。
脚本src =“ http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js”> / script>脚本src =“ http://documentcloud.github.com/backbone/主干min.js“> / script>脚本src =” http://documentcloud.github.com/underscore/underscore-min.js“> / script> script src =” https://raw.github.com/ jeromegn / Backbone.localStorage / master / backbone.localStorage-min.js“> / script>
本文中的以下所有代码都是特定于我们的应用程序的,因此我们可以将其包含在app.js文件中,或者如果您需要的话,只需内联即可。只需记住在Backbone之后将其包括在内即可。 Backbone能够抽象化我们的应用程序的各个部分,使它们既模块化又易于重用,并且对其他人更具可读性。为了最好地说明这种抽象,我们将从头开始,从模型开始,再以视图结束,从头开始解释FlickrBomb的设计。
我们的第一个模型
要解决的第一个任务是从Flickr中提取照片。在主干中对FlickrImage进行建模非常简单,我们将创建一个名为FlickrImage的新模型,并添加一些方法来帮助我们获得不同的大小。
var FlickrImage = Backbone.Model.extend({fullsize_url:function(){return this.image_url('medium');},thumb_url:function(){return this.image_url('square');},image_url:function( size){var size_code; switch(size){case'square':size_code ='_s'; break; // 75x75 case'medium':size_code ='_z'; break; //最长边为640'case ':size_code ='_b'; break; //最长的一侧默认为1024:size_code ='';}返回“ http:// farm” + this.get('farm')+“ .static.flickr.com /“ + this.get('服务器')+” /“ + this.get('id')+” _“ + this.get('秘密')+ size_code +” .webp“;}})
Backbone中的模型是可以持久化的对象,并且具有与之关联的某些功能,这与其他MVC框架中的模型非常相似。 Backbone模型的神奇之处在于我们可以将事件绑定到属性,以便当属性更改时,我们可以更新视图以反映这一点。但是,我们已经取得了一些进步。
当我们从Flickr中提取照片时,我们将获得足够的信息来创建所有尺寸的URL。但是该程序集由我们自己决定,因此我们实现了.image_url()函数,该函数采用size参数并返回公共链接。因为这是主干模型,所以我们可以使用this.get()访问模型上的属性。因此,使用此模型,我们可以在代码中的其他位置进行以下操作以获得Flickr图像的URL。
flickrImage.image_url(‘大’)
非常简洁,是吗?由于此模型专用于我们的应用程序,因此我们将为全尺寸和缩略图图像尺寸添加一些包装器功能。
图片集
FlickrBomb处理图像集合,而不是单个图像,而Backbone提供了一种方便的建模方法。恰当地命名为Collection的是我们用来将Flickr图像分组在一起的单个占位符。
var FlickrImages = Backbone.Collection.extend({模型:FlickrImage,键:flickrbombAPIkey,页面:1,提取:函数(关键字,成功){var self = this; success = success || $ .noop; this.keywords = keyword || this.keywords; $ .ajax({网址:“ http://api.flickr.com/services/rest/”,数据:{api_key:self.key,格式:“ json”,方法:“ flickr。 photos.search',标签:this.keywords,per_page:9,page:this.page,许可证:flickrbombLicenseTypes},dataType:'jsonp',jsonp:'jsoncallback',成功:function(response){self.add(response .photos.photo); success();}});},nextPage:function(callback){this.page + = 1; this.remove(this.models); this.fetch(null,callback);}, prevPage:function(callback){if(this.page> 1){this.page-= 1;} this.remove(this.models); this.fetch(null,callback);}}));
这里有几件事要注意。首先, 模型 属性告诉集合要收集的是哪种类型的模型。我们还有一些属性,我们稍后将对其进行初始化,以供以后使用:key是我们的Flickr API密钥,您将需要用自己的Flickr API密钥的字符串替换flickrbombAPIkey。获取Flickr API密钥既免费又容易,只需点击以下链接即可:www.flickr.com/services/api/misc.api_keys.html。页面属性是我们正在使用的Flickr照片的当前页面。
这里最大的方法是.fetch(),该方法抽象出了从Flickr API中提取照片的细节。为避免跨域请求出现问题,我们使用JSONP,Flickr API和jQuery均支持。我们传递给API的其他参数应该是不言自明的。特别感兴趣的是在这里调用的Backbone函数。在成功回调中,我们使用.add()这个函数,该函数接受一组模型属性,从这些属性创建模型实例,然后将它们添加到集合中。
.nextPage()和.prevPage()函数首先更改我们要显示的页面,
使用收集函数.remove(),从中删除所有现有模型
集合,然后调用fetch获取当前页面的照片(我们只是
更改)。
FlickrBombImage
继续工作,我们需要一个模型来表示占位符图像,该图像将包含FlickrImages的集合以及已选择的当前FlickrImage。我们将此模型称为FlickrBombImage。
var localStorage =(supports_local_storage())? new Store(“ flickrBombImages”):null; var FlickrBombImage = Backbone.Model.extend({localStorage:localStorage,initialize:function(){_.bindAll(this,'loadFirstImage'); this.flickrImages = new FlickrImages(); this.flickrImages.fetch(this.get('keywords'),this.loadFirstImage); this.set(id:this.get(“ id”)); this.bind('change:src',this.changeSrc) ;},changeSrc:function(){this.save();},loadFirstImage:function(){if(this.get('src')=== undefined){this.set({src:this.flickrImages。 first()。image_url()});}}});
由于此模型负责跟踪页面加载之间的当前选定图像,因此它需要知道要使用的本地存储。第一行将确保支持本地存储,然后创建将用于持久存储所选图像的存储。
Backbone允许我们定义一个.initialize()函数,该函数在创建模型实例时将被调用。我们在FlickrBombImage中使用此函数来创建FlickrImages集合的新实例,传递将用于此图像的关键字,然后从Flickr中获取图像。
当从Flickr加载图像时,已将.loadFirstImage()函数作为回调传递来运行。您可能会猜到,此函数将当前图像设置为Flickr集合中的第一幅图像。如果已经设置了当前图像,则不会执行此操作。
当此模型的src属性更改时,我们还将使用Backbone的属性回调来触发.changeSrc()函数。此回调所做的全部工作就是调用.save(),这是一个Backbone模型函数,该模型函数将模型的属性持久存储到已实现的任何存储层(在我们的示例中为localstore)。这样,无论何时更改所选图像,它都会立即保留。
视图层
现在,我们已经编写了所有后端(很好,前端后端)代码,我们可以将视图组合在一起。 Backbone中的视图与其他传统MVC框架中的视图略有不同。尽管视图通常只与表示有关,但骨干视图也负责行为。这意味着您的视图不仅定义了外观,而且还定义了与之交互时的功能。
视图通常(但不总是)绑定到某些数据,并经历三个阶段以从该数据生成表示标记:
1.初始化View对象,并创建一个空元素。
2.调用render函数,将视图插入到上一步中创建的元素中,从而为视图生成标记。
3.元素被附加到DOM。
似乎可能需要做很多工作来生成一些标记,而且我们甚至还没有涉及View的行为部分,但这很重要,这就是原因。每次修改DOM中的元素时,都会触发称为浏览器重排的操作。重排是浏览器重新计算页面上所有内容的位置。如果在拖动或调整大小事件中调用浏览器重排会降低性能,但间隔很短就会触发,但更糟糕的是,它们看起来很草率。通过复杂的页面操作,您实际上可以看到元素已添加到页面中,并实现了元素重新定位。遵循Backbone的初始化,渲染和附加模式,您可以保证一次重排,并且无论元素操作的复杂性如何,页面的更改都将立即感知到。
FlickrBombImageView
var FlickrBombImageView = Backbone.View.extend({tagName:“ div”,className:“ flickrbombContainer”,lock:false,template:_.template('div id =“%= this.image.id.replace(”“, “”)%>“ ... / div>'),初始化:函数(选项){_.bindAll(this,'addImage','updateSrc','setDimentions','updateDimentions'); var关键字=选项。 img.attr('src').replace('flickr://',``); this。$ el = $(this.el); this.image =新的FlickrBombImage({keywords:keyword,id:options。 img.attr('id')}); this.image.flickrImages.bind('add',this.addImage); this.image.bind('change:src',this.updateSrc);},事件:{ “ click .setupIcon”:“ clickSetup”,“ click .flickrbombFlyout a.photo”:“ selectImage”,“ click .flickrbombFlyout a.next”:“ nextFlickrPhotos”,“ click .flickrbombFlyout a.prev”:“ prevFlickrPhotos”},渲染:function(){$(this.el).html(this.template()); this.image.fetch(); this.resize(); return this;},...});
为了简洁起见,省略了该视图的功能,其源代码的完整信息可在GitHub上找到:github.com/zurb/flickrbomb
在视图的顶部,我们有几个特定于Backbone的属性。 tagName和className用于定义将应用于此View元素的标签和类。请记住,创建视图的第一步是创建对象,并且由于该创建是由Backbone处理的,因此我们需要指定元素和类。请注意,Backbone具有合理的默认值;如果我们省略这些属性,则默认情况下使用div,除非您指定一个,否则不会应用任何类。
template属性是约定,但不是必需的。我们在这里使用它来指定JavaScript模板函数,我们将使用该模板函数来为此视图生成标记。我们使用Underscore.js中包含的_.template()函数,但是您可以使用更喜欢的模板引擎,我们不会判断您。
在我们的.initialize()函数中,我们从图像标签中提取关键字字符串,然后使用这些关键字创建FlickrBombImage模型。当FlickrImage添加到FlickrImages集合中时,我们还将绑定要运行的.addImage()函数。此功能会将新添加的FlickrImage附加到我们的图像选择器弹出窗口。最后也是最重要的一行是绑定.updateSrc()函数,以在当前选择的FlickrImage更改时触发。在模型中更改当前图像后,此功能将运行,更新图像元素的src属性,然后CSS调整大小和裁剪图像以适合用户指定的图像尺寸。
事件:{“ click .setupIcon”:“ clickSetup”,“ click .flickrbombFlyout a.photo”:“ selectImage”,“ click .flickrbombFlyout a.next”:“ nextFlickrPhotos”,“ click .flickrbombFlyout a.prev”:“ prevFlickrPhotos “}
在.initialize()之后,我们具有View的行为部分。骨干网提供了一种使用事件对象绑定事件的便捷方法。 events对象使用jQuery .delegate()方法对View元素进行实际绑定,因此,无论您对视图内部的元素进行何种操作,所有绑定的事件仍然有效。它的工作原理与jQuery .live()相同,除了可以将事件绑定到任何元素的范围内,而不是将事件绑定到整个文档。事件对象中每个条目的键都由事件和选择器组成,该值指示应绑定到该事件的功能。请注意,.delegate()不适用于某些事件(如提交),请参阅jQuery .live()文档以获取受支持事件的完整列表。
渲染:function(){$(this.el).html(this.template()); this.image.fetch(); this.resize();返回此;}
最后,我们具有.render()函数,该函数负责创建我们的标记并执行在将View标记添加到View元素之前无法执行的任何其他工作。渲染模板后,我们需要在FlickrBombImage上调用.fetch()。 .fetch()是Backbone函数,它从持久层获取模型的最新副本。如果我们以前保存过此模型,.fetch()将立即检索该数据。提取图像后,我们需要调用调整大小以正确定位它。
家庭伸展
放置好所有片段之后,我们现在要做的就是在页面上找到占位符图像,并将其替换为呈现的FlickrBombImage视图。
$(“ img [src ^ ='flickr://']”).each(function(){var img = $(this),flickrBombImageView = new FlickrBombImageView({img:img}); img.replaceWith(flickrBombImageView。 render()。el);});
这个小片段需要在页面底部或在文档就绪回调中运行,以确保可以找到将替换的占位符图像。我们使用在图像标签的src属性中指定flickr:// [KEYWORD]的约定来指示应使用Flickr中的图像填充它。我们找到具有匹配src属性的图像元素,创建一个新的FlickrBombImageView,然后将图像替换为我们的图像元素。我们获取原始图像的副本并将其传递给FlickrBombView,以便我们可以提取可能已在元素上指定的一些其他配置选项。
所有辛勤工作的最终结果是为使用该库的人们提供了一个非常简单的API。他们可以使用flickr://约定简单地定义图像标签,将FlickrBomb代码放在页面底部,然后bam,他们从Flickr获得了占位符图像。
同样适用于大型OL Web应用程序
我们有一个名为Notable的大型OL网络应用程序,编写该应用程序时无需担心会生成客户端内容。当我们想通过生成内容客户端使应用程序的各个部分加速时,我们选择了Backbone。原因是相同的:我们想要一个轻量级的框架来帮助保持代码的组织性,而不是迫使我们重新考虑整个应用程序。
我们在今年早些时候取得了很大的成功,推出了这些更改,并且从那时起一直在赞美Backbones。
额外资源
除了我在本文中介绍的内容外,Backbone还有很多东西,MVC(模型视图控制器)的C(控制器)部分用于启动器,实际上,它是最新版本中的R(路由器)。骨干网文档中涵盖了所有内容,星期六星期六清晨,请阅读:
documentcloud.github.com/backbone/
如果您喜欢传统的教程,那么请查看用Backbone编写的此todo应用程序的文档记录得很好:
documentcloud.github.com/backbone/docs/todos.html