1.3 Ember.js概览
Ember.js起源于SproutCore框架的第二个版本。在SproutCore 2.0开发期间,SproutCore团队成员已经清楚地认识到,如果想要创建满足目标广泛的Web应用程序的需要,并且体积还保持小巧的易用框架,SproutCore框架的底层结构就需要有个根本改变。
SproutCore简介
SproutCore是一个用高度面向组件编程模型开发出来的框架。SproutCore的大多数概念都是从Apple的Cocoa借鉴来的,而Apple也使用SproutCore 来构建它的一些Web应用(MobileMe和iCloud)。同时,Apple还贡献了大量代码给SproutCore项目。2011年11月,Facebook得到了该项目团队并负责维护SproutCore。
最后,核心团队的部分成员决定从SproutCore分离出来,创建一个新的框架来实现这些改变。
Ember.js借鉴了SproutCore大量的底层结构和设计。但SproutCore为了创建桌面风格的应用程序,通过对开发者隐藏大部分实现细节来费力提供端到端解决方案,与此不同,Ember.js力求让开发者明白HTML和CSS才是开发栈里的核心。
Ember.js的优势在于能够让你以一致而可靠的模式组织JavaScript源代码,同时还保持着HTML与CSS代码的易见性。此外,不强制依赖特定工具来开发、构建及装配应用程序,给开发者更多的选择控制权来组织开发过程。在装配及打包应用程序时,有许多可靠的工具供选择。第11章将介绍一些有效的打包选项。
你迫不及待地想开始Ember.js编码了?但在创建你的第一个Ember.js应用程序之前,还是先来了解下Ember.js及其应用结构吧。
1.3.1 Ember.js特性
按照Ember.js官网①上的说法,Ember.js是一个帮助你构建“雄心勃勃”Web应用的框架。“雄心勃勃”这个词对不同的人可能有不同理解,但有一点是众所周知的,Ember.js的目标是挑战Web开发的极限,同时确保源代码的结构化和健壮性。
Ember.js将应用结构封装为逻辑抽象层,并强制尽可能采用面向对象开发模式,以达成其目标。其内置支持以下核心特性。
- 绑定——双向绑定的变量值将相互影响和更新。
- 计算属性——将方法标识为属性,并自动随其所依赖属性变化而更新。
- 自动更新模板——无论底层数据何时更改,始终确保界面处于最新状态。
将以上特性与强大而优良的MVC架构结合起来,你就获得了一个众望所归的Ember.js框架。
1.3.2 Ember.js应用程序结构
如果你曾经花费了大量时间通过服务器端生成标记及JavaScript代码来开发Web应用程序,Ember.js——一个全新亮相的JavaScript框架——其应用结构完全不同于旧有做法。
Ember.js包含了完整的MVC实现,MVC架构强化了控制器层和视图层。随着本章内容的推进,我们将涉及更多的MVC实现细节。
- 控制器层——构建路由与控制器的结合逻辑。
- 视图层——构建模板与视图的结合逻辑。
注意
第5章介绍的Ember Data,将充当Ember.js的模型层。
构建Ember.js应用程序时,开发者会对应用按一致而结构化的原则进行划分。可以花点时间考虑下放置应用逻辑的最佳位置。尽管这种方式要求在编码之前先仔细思考,但却能保证产品最终具有更好的结构,也就意味着程序易于维护。
大多数情况下,你将遵循Ember.js的指导原则和约定惯例,但有些情况下还需要花一些时间采取特别的方式来实现更复杂的应用功能。
如图1-6所示,Ember.js在标准MVC模型的各层之上引入了额外的概念,本书前5章会介绍这些概念。
记住这张图,我们来具体了解一下每个MVC组件。
1.模型与Ember Data
在图1-6的底部,Ember.js通过Ember Data来简化应用程序,Ember Data提供了创建富Web应用所需的大量数据-模型特性,其描绘了一种跟服务器端通信的可行实现方式。其他库也具备这种功能,你可以编写或引入你自己的客户端-服务器端通信层。Ember Data将在第5章中详细介绍,并在第6章介绍如何整合你自己的数据层。
模型层通常以半严格模式指定的方式来保存应用数据。模型层负责服务器端通信以及模型特有任务如数据转换。视图可以通过控制器绑定界面组件到模型对象属性。
Ember Data在模型层发挥作用,用来定义模型对象和客户端到服务器端的API,以及Ember.js与服务器端的传送协议(jQuery、XHR、WebSockets及其他)。
2.控制器与Ember路由器
在模型层之上是控制器层。控制器的主要作用是担当模型与视图之间的纽带。Ember.js附带了几个自定义控制器,最主要的是Ember.ObjectController和Ember.ArrayController这两个控制器。通常,当控制器描述单一对象时(如选择一条事项)使用ObjectController;而在控制器描述项目数组时(如列出当前用户所有有效事项)使用ArrayController。
在此之上,Ember.js通过路由器把应用程序分割为清晰界定的逻辑状态。每个路由可以有多个子路由,使用路由器在应用程序的不同状态间导航。
Ember路由器同时也是Ember.js用于更新应用程序URL以及监听URL变化的机制。使用Ember路由器的时候,将以类似状态图的层级结构来模型化所有应用状态。第3章将涉及Ember路由器的内容。
3.视图与Handlebars.js
视图层负责绘制界面元素。视图通常不保存自身永久状态,但也有极少例外。默认情况下,Ember.js中的每个视图都有一个对应的控制器作为其上下文。视图通过控制器获取数据,默认情况下,使用这个控制器来处理任何对该视图进行的用户操作。
同样是在默认情况下,Ember.js使用Handlebars.js作为其模板引擎。所以,大多数Ember.js应用程序通过Handlebars.js模板来定义用户界面。一个视图使用一个模板来渲染。第4章会介绍Handlebars.js和模板。
Handlebars.js
Handlebars.js基于Mustache,包括JavaScript在内的许多编程语言中都能看到无逻辑模板库Mustache的应用。Handlebars.js在Mustache之上添加了逻辑表达式(if、if-else、each等)。这样,随着可以将模板绑定到视图与控制器的属性上,开发者就能够为Ember.js应用构建逻辑清晰且可定制的结构化模板。
Ember.js附带了支持HTML5基本元素的默认视图,在处理简单元素时这些视图是非常合适的。而在构建Web应用复杂元素时,无论是扩展还是结合标准Ember.js视图,都能够很容易地创建出属于自己的自定义视图。
现在你了解了Ember.js应用程序结构,接下来开始编写你的第一个Ember.js应用。