zhenghao 2014-11-27
基本概念
在使用AngularJS之前,我们有必要梳理一下AngularJS核心概念及实现原理,以便于写出结构良好的代码。本章我们将结合简单的实例简要介绍Angular的重点概念,我们将附上AngularJS官方文档上的原文,帮助大家更好的理解概念:
实例讲解
接下来我们通过具体的实例讲解上面涉及的概念。
实例1: 数据绑定
<div ng-app ng-init="qty=1;cost=2">
<b>Invoice:</b>
<div>
Quantity: <input type="number" min="0" ng-model="qty">
</div>
<div>
Costs: <input type="number" min="0" ng-model="cost">
</div>
<div>
<b>Total:</b> {{qty * cost | currency}}
</div>
</div>页面预览:

让我们具体看上面的例子:
- AngularJS把上面的一段HTML看作一个"Template", 在HTML加载完成后,Angular从ng-app处启动应用,由Angular编译器"Compiler"解析新的标签或者属性,初始化Angular应用的上下文,绑定模型和视图。通过此过程加载、转换并展现出来的DOM就是所谓的视图。
- 新的标记被称为指令"Directive",这种标记通过AngularJS被赋予了某些特殊行为。例如 "ng-app"触发Angular自动初始化相应的应用模块, 如下图所示:

- Angular内建了指令给<input>添加了额外的行为。
- ng-model指令绑定了作用域内同名的属性,在这个例子中input中的text发生改变,绑定的model(qty | cost)值也随之更新, 反之亦然。
- {{ expression | filter }} AngularJS会这类标记识别成表达式和过滤器,表达式类似于JS片段,允许我们 读写作用域内的模型(model),如例子所示,我们通过表示可以看到input的中绑定的变量的乘积。
- 上述表达式还有个filter,用于前面的表达式结果进行格式化输出, 用法类似于Linux里面的管道"|".
该例子展示了AngularJS的双向数据绑定. 当input值改变时,会重新计算表达式并在DOM中实时更新。
实例二: 基于实例1 通过Controller加入逻辑
实现Controller (invoice.js)
angular.module('invoice', [])
.controller('InvoiceController', function() {
this.qty = 1;
this.cost = 2;
this.inCurr = 'EUR';
this.currencies = ['USD', 'EUR', 'CNY'];
this.usdToForeignRates = {
USD: 1,
EUR: 0.74,
CNY: 6.09
};
this.total = function total(outCurr) {
return this.convertCurrency(this.qty * this.cost, this.inCurr, outCurr);
};
this.convertCurrency = function convertCurrency(amount, inCurr, outCurr) {
return amount * this.usdToForeignRates[outCurr] / this.usdToForeignRates[inCurr];
};
this.pay = function pay() {
window.alert("Thanks!");
};
});
HTML
<div ng-app="invoice" ng-controller="InvoiceController as invoice">
<b>Invoice:</b>
<div>
Quantity: <input type="number" min="0" ng-model="invoice.qty" required >
</div>
<div>
Costs: <input type="number" min="0" ng-model="invoice.cost" required >
<select ng-model="invoice.inCurr">
<option ng-repeat="c in invoice.currencies">{{c}}</option>
</select>
</div>
<div>
<b>Total:</b>
<span ng-repeat="c in invoice.currencies">
{{invoice.total(c) | currency:c}}
</span>
<button class="btn" ng-click="invoice.pay()">Pay</button>
</div>
</div>
实例讲解:
- 在这个例子中我们我们实现了名为"invoice1"的应用模块名在页面中通过ng-app指令引入. 在"invoice1"模块中定义了"InvoiceController"控制器,并通过ng-controller在页面中绑定, 注意ng-controller必须出现在和"invoice1"绑定的元素或者子元素中. 控制器暴露了该模块作用域内可以使用的变量或者函数(this.*)给相应的表达式和指令.
- Angular提供controller()构造器给我们实现自己的Controller.
- 在ng-controller我们用“InvoiceController as invoice” 给controller去了个别名,通知AngularJS在注入器给该控制器的实例取名为invoide,在HTML子元素中可以通过别名引用控制器里面的变量或者函数。
- 我们同样注意到ng-repeat指令,可定绑定数组或者对象类型,迭代DOM操作
- ng-click是另外一个AngularJS指令,在相应DOM上绑定click时间及与之对应的行为。
工作原理如下图所示:

实例三 : 基于实例二将于View无关的业务逻辑抽取到service组件里面
但应用变得愈加复杂的时候有必要把与视图无关的业务逻辑抽取成service组件,有经验的程序员可以联想JAVA EE或者.NET中的MVC架构。这些service是可以重用的。让我们重构一下上面的代码:
1. 将finance领域相关的逻辑抽取成finance.js
angular.module('finance', [])
.factory('currencyConverter', function() {
var currencies = ['USD', 'EUR', 'CNY'];
var usdToForeignRates = {
USD: 1,
EUR: 0.74,
CNY: 6.09
};
var convert = function (amount, inCurr, outCurr) {
return amount * usdToForeignRates[outCurr] / usdToForeignRates[inCurr];
};
return {
currencies: currencies,
convert: convert
};
});
2. 简化invoice.js的代码如下:
angular.module('invoice', ['finance'])
.controller('InvoiceController', ['currencyConverter', function(currencyConverter) {
this.qty = 1;
this.cost = 2;
this.inCurr = 'EUR';
this.currencies = currencyConverter.currencies;
this.total = function total(outCurr) {
return currencyConverter.convert(this.qty * this.cost, this.inCurr, outCurr);
};
this.pay = function pay() {
window.alert("Thanks!");
};
}]);我们分析一下重构的代码:
1. 我们把convertCurrency函数挪到了finance.js中,利用依赖注入机制在controller的构造函数中声明注入finance service对象。Angular组件都可以通过依赖注入的方式(injector)连接起来。
2. 提到依赖注入,我们肯定想到一定会有个地方(容器)注册、存放、管理依赖,AngularJS通过模块(module)把相关的组件放到一起。在Angular启动应用时,会通过ng-app的配置项,已经定义在module代码里面的配置项初始化容器。
3. 在上面的例子中ng-app="invoice"这个指令告诉Angular用invoice模块作为应用的主模块。代码angular.module('invoice', ['finance'])声明invoice模块依赖finance模块,即InvoiceController中用到了finance模块中的currencyConverter服务controller('InvoiceController', ['currencyConverter',function....]。
4. AngularJS提供了多种方式声明依赖,本例通过构造函数的参数列表中定义依赖,最后一个参数为构造函数。
5. 本例中通过AngularJS的factory方法定义service, 例如factory('currencyConverter', function(){...}, 在后续的例子中我们将会详解service.
本例具体原理如下图所示:

以上示例来自于官方文档,在后续的章节中我们将结合更多具体的代码示例详解每个具体的概念。
问题描述在编写导入指令的时候,需要将函数绑定到指令中,并传入一个参数。<button ng-hide="importing" class="btn btn-warning btn-sm" type="