数据绑定和第一个 AngularJS Web应用

Hello World
写一个Hello World应用是开始学习AngularJS的最基本途径,让我们从一段简单得不能再简单
的HTML开始吧。
随着学习的深入,我们会逐渐深入到AngularJS的内部原理中。 现在, 让我们先来写一个Hello
World应用。
<!DOCTYPE html>
<html ng-app>
<head>
<title>Simple app</title>
<script
src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.13/angular.js">
</script>
</head>
<body>
<input ng-model="name" type="text" placeholder="Your name">
<h1>Hello {{ name }}</h1>
</body>
</html>
图2-1 Hello World
虽然这个例子不怎么有趣,但它展示了AngularJS最基本也最令人印象深刻的功能之一: 数

据绑定。

请注意,在本章的示例代码中为了方便展示第一个核心概念,我们并没有用最
佳方式编写控制器。这也是本书唯一一处我们不鼓励将示例代码应用在实际生
产中,而只作为学习范例的地方。
2.1 AngularJS 中的数据绑定
在Rails等传统Web框架中,控制器将多个模型中的数据和模板组合在一起形成视图,并将其
提供给用户,这个组合过程会产生一个单向视图。如果没有创建任何自定义的JavaScript组件,视
图只会体现它渲染时模型暴露出的数据。在写这篇文章时,已经出现了好几个可以在视图和模型
之间自动进行数据绑定的框架。
AngularJS则采用了完全不同的解决方案。它创建实时模板来代替视图,而不是将数据合并
进模板之后更新DOM。任何一个独立视图组件中的值都是动态替换的。这个功能可以说是
AngularJS中最重要的功能之一,也是让我们只用10行代码,并且在没有任何JavaScirpt的情况下
就可以写出Hello World的关键。
要实现这个功能,只要在HTML页面中引用angular.js,并在某个DOM元素上明确设置
ng-app属性即可。 ng-app属性声明所有被其包含的内容都属于这个AngularJS应用,这也是我们
可以在Web应用中嵌套AngularJS应用的原因。只有被具有ng-app属性的DOM元素包含的元素才
会受AngularJS影响。
视图中的插值会在计算一个或多个变量时被动态替换,替换结果是字符串中的
插值被变量的值替代。
例如,如果有一个叫做name的变量,它的值是“ Ari”,那么视图中的"Hello
{{ name }}"字符串会被替换成“ Hello Ari”。
自动数据绑定使我们可以将视图理解为模型状态的映射。当客户端的数据模型发生变化时,
视图就能反映出这些变化,并且不需要写任何自定义的代码,它就可以工作。
在MVC(Model View Controller,模型视图控制器)的世界里,控制器可以不必担心会牵
扯到渲染视图的工作。这样我们就不必再担心如何分离视图和控制器逻辑,并且也可以使测试变
得既简单又令人愉悦。
MVC是一种软件架构设计模式,它将表现从用户交互中分离出来。通常来讲,
模型中包含应用的数据和与数据进行交互的方法,视图将数据呈献给用户,而
控制器则是二者之间的桥梁。
这种表现分离①能将应用中的对象很好地隔离开来,因此视图不需要知道如何保
存对象,只要知道如何显示它即可。这也意味着数据模型不需要同视图进行交
互,只需要包含数据和操作视图的方法。控制器用来存放将二者绑定在一起的
业务逻辑。

AngularJS①会记录数据模型所包含的数据在任何特定时间点的值(在Hello World例子中就是
name的值),而不是原始值。
当AngularJS认为某个值可能发生变化时,它会运行自己的事件循环来检查这个值是否变
“脏”。如果该值从上次事件循环运行之后发生了变化,则该值被认为是“脏”值。这也是Angular
可以跟踪和响应应用变化的方式。
这个事件循环会调用$digest()循环,第23章将会详细介绍。
这个过程被称作脏检查(dirty checking) 。脏检查是检查数据模型变化的有效手段。当有潜
在的变化存在时, AngularJS会在事件循环时执行脏检查(第24章会深入讨论)来保证数据的一
致性。
如果使用KnockoutJS这种通过在数据模型上绑定事件监听器来监听数据变化的框架,这个
过程会变得更复杂且低效②。处理事件合并、依赖跟踪和大量的事件触发(event firing)是非常复
杂的,而且会在性能方面导致额外的问题。
尽管存在更高效的方式,但脏检查可以运行在所有浏览器中并且是可预测的。
此外,很多在速度和效率方面有要求的软件都会使用脏检查的方案③。
借助AngularJS,不需要构建复杂和新的JavaScript功能,就可以在视图中实现类自动同步的
机制。
为了表示内部和内置的库函数,Angular使用$预定义对象。尽管这类似于全局的jQuery
对象$,但它们是完全无关的。只要遇到$符号,你都可以只把它看作一个Angular对象。
2.2 简单的数据绑定
审阅一下上面写的代码,我们使用ng-model指令将内部数据模型对象($scope)中的name
属性绑定到了文本输入字段上。
这意味着无论在文本输入字段中输入了什么,都会同步到数据模型中。
数据模型对象(model object)是指$scope对象。 $scope对象是一个简单的
JavaScript对象,其中的属性可以被视图访问,也可以同控制器进行交互。如果
不理解这个概念也没有关系,后面的例子将会对这个概念进行详细说明。
双向数据绑定(bi-directional)意味着如果视图改变了某个值,数据模型会通过
脏检查观察到这个变化,而如果数据模型改变了某个值,视图也会依据变化重
新渲染。
在输入字段上使用ng-model指令来实现数据绑定,如下所示:

<input ng-model="person.name" type="text" placeholder="Yourname">
<h1>Hello{{ person.name }}</h1>
这样绑定就设置好了(没错,就是这么简单)。我们可以观察一下视图是如何更新数据模型
的。当输入字段中的值发生变化时, person.name会被更新,而视图将反映出这个更新。
我们仅通过视图就实现了一个双向数据绑定。为了从其他角度(后端到前端)解释双向数据
绑定,后面会深入介绍控制器。
正 如 ng-app 声 明 所 有 被 它 包 含 的 元 素 都 属 于 AngularJS 应 用 一 样 , DOM 元 素 上 的
ng-controller声明所有被它包含的元素都属于某个控制器。
为了解释这个概念,我们将前面的例子修改成如下的样子:
<div ng-controller='MyController'>
<input ng-model="person.name" type="text" placeholder="Your name">
<h1>Hello {{ person.name }}</h1>
</div>
在这个例子中,我们会创建一个每秒钟走一步的时钟(时钟通常都是这样的) ,并更新clock
变量上的数据:
function MyController($scope, $timeout) {
var updateClock = function() {
$scope.clock = new Date();
$timeout(function() {
updateClock();
}, 1000);
};
updateClock();
};
在这个例子中, MyController函数接受两个参数,即该DOM元素的$scope和
$timeout。第13章将介绍如何使用不同的变量定义函数。
在这个例子中,当定时器触发时会调用updateClock()函数,将$scope.clock的值设置为当
前时间。
 $timeout对象
可以在视图中将clock变量用{{ }}包起来,以显示$scope中的clock的值:
<div ng-controller="MyController">
<h5>{{ clock }}</h5>
</div>
下面是完整的示例代码:
<!doctype html>
<html ng-app>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.13/angular.js"></script>
</head>
<body>
<div ng-controller="MyController">
<h1>Hello {{ clock }}!</h1>

</div>
<script type="text/javascript">
function MyController($scope, $timeout) {
var updateClock = function() {
$scope.clock = new Date();
$timeout(function() {
updateClock();
}, 1000);
};
updateClock();
};
</script>
</body>
</html>
在线示例: http://jsbin.com/uHiVOZo/1/edit?html,output。
尽管我们可以将所有代码都写在一个文件中,但由于需要将不同的组件分开开
发,将代码写在一个文件中会使协同工作变得非常困难。通常情况下,更好的
选择是将JavaScript放在单独的文件中,而不是index.html中。
上面的代码可以修改成:
<!doctype html>
<html ng-app>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.13/angular.js"></script>
</head>
<body>
<div ng-controller="MyController">
<h1>Hello {{ clock }}!</h1>
</div>
<script type="text/javascript" src="js/app.js"></script>
</body>
</html>
将前面例子中的JavaScript代码放在js/app.js文件中,而不是将它直接写在HTML中。
// 在app.js中
function MyController($scope, $timeout) {
var updateClock = function() {
$scope.clock = new Date();
$timeout(function() {
updateClock();
}, 1000);
};
updateClock();
};
2.3 数据绑定的最佳实践
由于JavaScript自身的特点,以及它在传递值和引用时的不同处理方式,通常认为,在视图中
通过对象的属性而非对象本身来进行引用绑定,是Angular中的最佳实践。

如果把这个最佳实践应用到上面时钟的例子中,需要把视图中的代码改写成下面这样:
<!doctype html>
<html ng-app>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.13/angular.js"></script>
</head>
<body>
<div ng-controller="MyController">
<h1>Hello {{ clock.now }}!</h1>
</div>
<script type="text/javascript" src="js/app.js"></script>
</body>
</html>
在这个例子中,相比每秒钟都更新$scope.clock,更新clock.now的值会是更好的选择。有
了这个优化后,我们将反映数据变化的逻辑做如下修改:
// 在app.js中
function MyController($scope) {
$scope.clock = {
now: new Date()
};
var updateClock = function() {
$scope.clock.now = new Date()
};
setInterval(function() {
$scope.$apply(updateClock);
}, 1000);
updateClock();
};
将所有绑定都通过这样的形式放在视图中,是个非常好的主意。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值