从 Backbone.js 开始
与 Web 开发同行不同,JavaScript 从来没有真正以框架的方式提供结构。值得庆幸的是,近年来,这种情况开始发生变化。
今天,我想向您介绍 Backbone.JS,这是一个可爱的小库,它使创建复杂、交互式和数据驱动的应用程序的过程变得更加容易。它提供了一种干净的方法来将数据与演示文稿分离。
Backbone.JS 概述
Backbone 由构建 CoffeeScript 的 JS 忍者 Jeremy Ashkenas 创建,是一个超轻量级库,可让您创建易于维护的前端。它与后端无关,并且可以与您已经使用的任何现代 JavaScript 库配合良好。
Backbone 是一个内聚对象的集合,重量4kb以下,它为您的代码提供结构,基本上可以帮助您在浏览器中构建适当的 MVC 应用程序。官方网站是这样描述其目的的:
Backbone 通过提供具有键值绑定和自定义事件的模型、具有丰富的可枚举函数 API 的集合、具有声明性事件处理的视图,为 JavaScript 密集型应用程序提供结构,并将其全部连接到您现有的应用程序RESTful JSON 接口。
让我们面对现实:上面的内容有点难以解析和理解。因此,让我们在 Jeremy 的帮助下继续解构这些行话。
键值绑定和自定义事件
当模型的内容或状态发生更改时,已订阅该模型的其他对象会收到通知,以便它们可以进行相应的处理。在这里,视图监听模型中的变化,并相应地更新自己,而不是模型必须手动处理视图。
丰富的可枚举函数API
Backbone 附带了许多非常有用的函数来处理和使用您的数据。与其他实现不同,JavaScript 中的数组是相当中性的,当您必须处理数据时,这确实是一个阻碍问题。
具有声明性事件处理的视图
你编写意大利面条式绑定调用的日子已经结束了。您可以通过编程方式声明哪个回调需要与特定元素关联。
RESTful JSON 接口
尽管当您想要与服务器通信时默认方法是使用标准 AJAX 调用,但您可以轻松地将其切换为您需要的任何内容。许多适配器如雨后春笋般涌现,涵盖了大多数最受欢迎的适配器,包括 Websockets 和本地存储。
将其分解为更简单的术语:
Backbone 提供了一种干净的方法来将数据与演示文稿分离。处理数据的模型只关心与服务器同步,而视图的主要职责是监听订阅模型的更改并呈现 HTML。
快速常见问题解答
我猜您现在可能有点困惑,所以让我们澄清一些事情:
它会取代 jQuery 吗?
没有。它们的范围非常互补,功能上几乎没有重叠。 Backbone 处理所有更高级别的抽象,而 jQuery(或类似的库)则处理 DOM、规范化事件等。
它们的范围和用例非常不同,因为你知道其中一个并不意味着你不应该学习另一个。作为一名 JavaScript 开发人员,您应该知道如何有效地使用两者。
我为什么要使用这个?
因为通常情况下,前端代码会变成一堆热气腾腾、脏兮兮的嵌套回调、DOM 操作、用于演示的 HTML 以及其他不可言喻的行为。
Backbone 提供了一种非常干净和优雅的方式来管理这种混乱。
我应该在哪里使用它?
Backbone 非常适合创建前端重型、数据驱动的应用程序。想想 GMail 界面、新 Twitter 或过去几年的任何其他启示。它使创建复杂的应用程序变得更加容易。
虽然您可以将其硬塞到更主流的网页页面,但这实际上是一个专为网络应用程序量身定制的库。
它与卡布奇诺或 Sproutcore 类似吗?
是和否。
是的,因为与上面提到的框架一样,这主要用于为 Web 应用程序创建复杂的前端。
它的不同之处在于 Backbone 非常精简,并且没有附带其他小部件。
Backbone 的重量非常轻,不到 4kb。
还有一个事实是,Cappuccino 强制您使用 Objective-J 编写代码,而 Sproutcore 的视图必须在 JS 中以编程方式声明。虽然这些方法都没有错,但使用 Backbone,普通的 JavaScript 可以通过常用的 HTML 和 CSS 来完成工作,从而实现更温和的学习曲线。
我仍然可以在页面上使用其他库,对吧?
绝对是的。不仅是典型的 DOM 访问、AJAX 包装类型,还有其余的模板和脚本加载类型。它的耦合非常非常松散,这意味着您可以将几乎所有工具与 Backbone 结合使用。
它会带来世界和平吗?
不,抱歉。但这里有一些东西可以让你振作起来。
好的,现在抛开这个问题,让我们开始吧!
了解 Backbone 的 Backbone
Backbone 中的 MVC 最初代表模型、视图和集合,因为框架中没有控制器。此后情况发生了变化。
Backbone 的核心由四个主要类组成:
- 型号
- 集合
- View
- 控制器
由于我们时间有点紧张,所以我们今天只看一下核心课程。我们将使用一个超级简单的应用程序进行后续操作,以演示此处教授的概念,因为将所有内容都放在一篇文章中并期望读者解析所有内容会太多。
在接下来的几周内请保持警惕!
型号
模型在不同的 MVC 实现中可能有不同的含义。在 Backbone 中,模型代表一个单一实体——数据库中的记录(如果您愿意的话)。但这里没有硬性规定。来自 Backbone 网站:
模型是任何 JavaScript 应用程序的核心,包含交互式数据以及围绕它的大部分逻辑:转换、验证、计算属性和访问控制。
该模型只是为您提供了一种在数据集上读取和写入任意属性或属性的方法。考虑到这一点,下面的单行代码是完全可用的:
var Game = Backbone.Model.extend({});
让我们在此基础上进一步发展。
var Game = Backbone.Model.extend({ initialize: function(){ alert("Oh hey! "); }, defaults: { name: 'Default title', releaseDate: 2011, } });
initialize 将在实例化对象时被触发。在这里,我只是提醒大家注意一些愚蠢的行为——在您的应用程序中,您可能应该引导数据或执行其他内务处理。我还定义了一堆默认值,以防没有数据被传递。
我们来看看如何读写属性。但首先,让我们创建一个新实例。
// Create a new game var portal = new Game({ name: "Portal 2", releaseDate: 2011}); // release will hold the releaseDate value -- 2011 here var release = portal.get('releaseDate'); // Changes the name attribute portal.set({ name: "Portal 2 by Valve"});
如果您注意到 get/set 变异器,请吃一块 cookie!无法通过典型的 object.attribute 格式读取模型的属性。您必须执行 getter/setter,因为错误更改数据的可能性较低。
此时,所有更改仅保留在内存中。让我们通过与服务器对话来使这些更改永久生效。
portal.save();
就是这样。你期待更多吗?上面的一行代码现在将向您的服务器发送一个请求。请记住,请求的类型会智能地改变。由于这是一个新对象,因此将使用 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 的模型。您可以通过引用 at 方法的索引来查找特定位置的元素,如下所示: 游戏.at(0);
最后,您可以像这样动态填充您的集合:
var GamesCollection = Backbone.Collection.extend({ model : Game, url: '/games' } }); var games = new GamesCollection games.fetch();
我们只是让 Backbone 通过 url 属性从何处获取数据。完成后,我们只需创建一个新对象并调用 fetch 方法,该方法会触发对服务器的异步调用并使用结果填充集合。
这应该涵盖 Backbone 集合的基础知识。正如我提到的,这里有大量的好东西,其中 Backbone 别名了 Underscore 库中的许多漂亮的实用程序。快速阅读官方文档应该可以帮助您入门。
查看
乍一看,Backbone 中的视图可能会有些混乱。对于 MVC 纯粹主义者来说,它们类似于控制器而不是视图本身。
视图从根本上处理两项职责:
- 监听 DOM 和模型/集合抛出的事件。
- 向用户展示应用的状态和数据模型。
让我们继续创建一个非常简单的视图。
GameView= Backbone.View.extend({ tagName : "div", className: "game", render : function() { // code for rendering the HTML for the view } });
如果您到目前为止一直在学习本教程,那么相当简单。我只是通过 tagName 属性指定应该使用哪个 HTML 元素来包装视图,并通过 className 指定它的 ID。
让我们继续进行渲染部分。
render : function() { this.el.innerHTML = this.model.get('name'); //Or the jQuery way $(this.el).html(this.model.get('name')); }
el 指的是视图引用的 DOM 元素。我们只是通过元素的 innerHTML 属性访问游戏的名称。简而言之,div 元素现在包含我们游戏的名称。显然,如果您以前使用过该库,则 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 }
如果您以前处理过事件,那么应该很简单。我们基本上是通过事件对象定义和连接事件。正如您在上面看到的,第一部分指的是事件,下一部分指定触发元素,最后一部分指应触发的函数。
现在绑定到模型和集合。我将在这里介绍模型的绑定。
GameView= Backbone.View.extend({ initialize: function (args) { _.bindAll(this, 'changeName'); this.model.bind('change:name', this.changeName); }, });
首先要注意的是我们如何将绑定代码放置在初始化函数中。当然,最好从一开始就这样做。
bindAll 是 Underscore 提供的一个实用程序,用于保存函数的 this 值。这特别有用,因为我们传递了一堆函数,并且指定为回调的函数已删除该值。
现在,只要模型的 name 属性发生更改,就会调用 changeName 函数。您还可以使用添加和删除动词来轮询更改。
侦听集合中的更改就像将处理程序绑定到回调时将模型替换为集合一样简单。
控制器
Backbone 中的控制器本质上允许您使用 hashbang 创建可添加书签的有状态应用程序。
var Hashbangs = Backbone.Controller.extend({ routes: { "!/": "root", "!/games": "games", }, root: function() { // Prep the home page and render stuff }, games: function() { // Re-render views to show a collection of books }, });
这对于传统服务器端 MVC 框架中的路由非常熟悉。例如,!/games 将映射到 games 函数,而浏览器本身中的 URL 将是 domain/#!/games。
通过智能使用 hashbang,您可以创建大量基于 JS 且可添加书签的应用程序。
如果您担心破坏后退按钮,Backbone 也能满足您的需求。
// Init the controller like so var ApplicationController = new Controller; Backbone.history.start();
通过上面的代码片段,Backbone 可以监控您的 hashbang,并结合您之前指定的路线,使您的应用程序可添加书签。
我从 Backbone 学到了什么
总的来说,以下是我从创建应用程序的 Backbone 方式中学到的一些经验教训:
- 前端确实需要 MVC。传统方法给我们留下的代码过于耦合、混乱且难以维护。
- 在 DOM 中存储数据和状态是一个坏主意。在创建需要使用相同数据更新应用的不同部分的应用后,这开始变得更有意义。
- 胖模型和瘦控制器是正确的选择。当业务逻辑由模型处理时,工作流程就会得到简化。
- 模板是绝对必要的。将 HTML 放入 JavaScript 中会给您带来不好的业力。
可以说 Backbone 引起了前端构建方式的范式转变,至少对我来说是这样。鉴于今天文章的范围非常广泛,我确信您有很多问题。点击下面的评论部分来插话。非常感谢您的阅读,并期待将来有更多的 Backbone 教程!
从 Backbone.js 开始的详细内容,更多请关注红帽云邮其它相关文章!