本节书摘来自异步社区《Ember.js实战》一书中的第2章,第2.1节,作者:【挪】Joachim Haagen Skeie(乔基姆•哈根•斯基)著,更多章节内容可以访问云栖社区“异步社区”公众号查看
第2章 Ember.js风格
本章涵盖的内容
- 绑定的工作方式,以及它们对编程风格的影响
- 自动更新模板的使用
- 如何及何时使用计算属性及观察者(Observer)模式
- Ember.js对象及类模型
本章将在第1章代码的基础上详细阐述Ember.js框架中最具特色的知识点。Ember.js最关键的设计目标之一就是提供完整、合理的默认实现以避免开发者必须自己创建大量样板代码。Ember.js通过默认设置来满足大多数Web应用的需要,并允许开发者在合适之处轻松覆写这些默认设置。有了这些完备选择,我们就可以大大降低编写各种Web应用程序的难度,从此不用过多纠结于数据如何从A传到B,也不用再老想着如何以清晰而高效的方式更新HTML元素,同时,还能够方便地集成第三方JavaScript框架。
如果你接触过诸如Objective-C、Adobe Flex以及JavaFX这些具备绑定功能的其他编程环境,那么在应用中运用观察者模式、约束变量以及数据自动同步等方法对你而言应该再熟悉不过了。否则,你得忘掉旧有编程习惯并接受Ember.js基本概念,因为这些概念将彻底改变你编写程序的思维方式。改变编程习惯以适应松耦合及异步编程思维方式,应该是学习高效运用Ember.js的最大难点。
图2-1列出了本章涉及的Ember.js功能模块——ember-application、ember-views以及Handlebars.js。
本章将进一步完善第1章创建的记事本应用程序。 更新代码放在index4.html和app4.js文件中。
我们先从绑定这个核心特性入手,它是整个Ember.js框架的基础。
Ember.js框架基于相关联的几个特性来整合框架并提供其他特性。掌握绑定、计算属性及观察者模式的工作方式,是Ember.js程序员的必备技能。
2.1 绑定对象
最常见的任务可能就是不断重复编写Web应用代码请求服务器端数据,解析响应信息并调用控制器,确保视图在数据改变时同步更新。
然后,当用户使用这些数据的时候,还得在某种程度上同时更新浏览器缓存及视图数据,这样才能确保浏览器缓存数据与页面展示数据保持一致。
你可能已经为成百上千的用户案例编写过代码,但是大多数的Web应用程序仍缺乏一个网站级的底层结构以一种清晰而一致的方式来处理各种交互,这就导致开发者为每个应用、应用各层重复造轮子。通常的实现如图2-2所示。
该模型假设你已经思考过要如何组织应用程序,并且已经在应用程序中实现了一个MVC结构。Ember.js的MVC模型与你以往开发Web应用时惯用的MVC模型稍有不同,但不用害怕,第3章将详细讲解Ember.js的MVC模型。
图2-2所示模型存在一个问题,开发者得自己实现一个结构来确保保存到服务器端的数据与展示给用户的数据是一致的。此外,还需为列出的6个步骤(步骤3~8)逐一编写代码。考虑一下各种边界情况。
- 如果服务器端无法保存数据会怎样?
- 如果在加载数据(步骤2)与保存数据(步骤5)之间服务器端却更新了数据,那会怎样?
- 如果用户创建了新数据并且服务器端需要为数据生成唯一标识符,那会怎样(步骤3和5)?
- 如果服务器端更新了一些数据,那么客户端如何及时获取通知以反映这种更新?
- 如果数据发送给服务器端后,用户马上进行了更改操作,但此时服务器端响应还未返回客户端,这时候会发生什么?
- 如果控制器未获得改变通知而模型却发生了改变,那会怎样?
- 如果多个视图需要展示同一数据会怎样?如何同步数据来保持用户界面的一致性?
这些只是需要在应用各个环节都要判别的几个例子。如果你打算在开发中实现通常的数据同步解决方案,那真是了不起!现在,你了解了在视图与控制器、模型与模型、客户端与服务器端之间同步应用数据的困难所在。而Ember.js凭其完整而健壮的绑定机制与MVC实现,特别适合在此类场景中发挥直接作用。Ember.js还提供了完整持久层Ember Data,我们将在第5章讨论它。
最简单的形式是,通过绑定方式告知应用程序“当变量A改变时,请确保同步更新变量B”。Ember.js的绑定可以是单向或双向的,两者的工作方式相同,但双向绑定无论哪个变量发生改变,都会在两个变量间保持同步。Ember.js中最常用的绑定类型可能就属双向绑定了,因为它是Ember.js的默认绑定结构,此外,编写客户端应用时也最可能需要双向绑定。
可以调用Ember.Binding.twoWay或Ember.Binding.oneWay函数来明确声明一个绑定;在创建单向绑定时需要这么做。而大多数情况下,我们在对象属性声明里通过Binding后缀关键字来创建双向绑定。Ember.js的构造足够聪明,现实中很少出现需要手动实例化绑定对象的情况。因此,在第1章开发的记事本应用程序里,并不需要手动创建绑定。
然而,假设你打算在Notes.NotesController上跟踪我们选择了哪条事项,可以绑定一个属性(如selectedNote)到Notes.NotesController 的模型对象上。代码清单2-1修改了NotesController。
代码清单2-1 通过绑定同步两个变量
如果重新加载应用程序并打开浏览器控制台,将看到如图2-3所示的结果。
Ember.js会输出应用程序使用的Ember.js、Handlebars.js以及jQuery版本号。当Ember.js实例化控制器和路由,Ember.js会把它们放进一个叫容器(container)的结构。你可以请求容器查找NotesController实例并检查selectedNote属性值。在控制台输入以下命令并回车,图2-4显示了结果。
selectedNote属性返回空值。这是预期结果,因为此时尚未选择事项。现在,选择一条事项并再次执行上条命令,图2-5显示了结果。
现在可以通过NotesController的selectedNote属性获取所选事项了。注意,还可以通过调用get('selectedNote.id')获取所选事项的id属性。通过点记法可以深入对象继承链查找及更新属性值①。
尽管只在代码清单2-1中添加了一条语句,但Ember.js却帮你实现了以下特性。
- 在两个控制器之间实现了双向绑定,当改变发生时保持变量同步。
- 清晰的控制器间关系界定。
- 通过实现控制器间的松耦合,达成了高度的可测试性及应用灵活性。
- 在整个应用中,选择了哪条事项只有一个确定结果;明确了SelectedNote- Controller.model②将总是代表所选事项这一规则,将让你能够创建无论所选事项何时发生改变都可以自动更新的视图。
接下来,我们添加一些代码行,以了解通过自动更新模板将数据绑定到视图的方式。