angular学习(一)—— 概览


这篇主要通过几个小例子把angular的常用组件简单介绍一下

data binding

下面是一个简单通过quantity和costs计算Total的示例

1
2
3
4
5
6
7
8
9
10
11
12
<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>

输出结果

输出结果

下面描述一下这段代码是如何运行的,这段代码看起来像一个带着一些新的标记的普通html文件,在angular中,这样的文件叫template,当angular运行时,它会从这个template中去解析处理这些新的标记,并且加载、转换和呈现以dom的形式。
面的例子还包含了一个filter,filter的作用主要是把表达式的值展现给用户,在这个例子中currency filter将数值最终转换为货币格式输出

这里写图片描述

第一种标记在angular中被称为directives,他们为一些属性或者元素增加特殊的功能,比如上面的ng-app属性,angular识别到它会自动初始化为angular应用程序。angular也为input元素增加一些扩展的功能,比如接下来的ng-model,他可以将input的值存储到一个变量中,也可以把变量的值赋予到input中,这这绑定是live的绑定,一个变化另一个随之变化,称之为双向绑定。

第二种标记是带双花括号的 {‍{ expression | filter }‍},当angular的编译器遇到这种标记时会用表达式最终的值去代替这个标记。在template中的表达式是一种类javascript的变量,angular可以对这些表达式进行读写。应该注意的是这些变量都不是全局变量,仅仅就像是javascript函数中的变量一样。angular给这些变量scope的概念,以便让他们以model的形式在文档的其他部分可以访问到。对于这个例子来说,angular对这些directives的理解就是:把两个输入框的值取出来然后相乘。

上面的例子还包含了一个filter,filter的作用主要是把表达式的值展现给用户,在这个例子中currency filter将数值最终转换为货币格式输出

页面逻辑:Controllers

让我们增加一些逻辑,可以用不同的货币输入,计算和支付这个货单。

index.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<div ng-app="invoice1" 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.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
angular.module('invoice1', [])
.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!");
};
});

输出
这里写图片描述
在javascript文件中包含了一个controller,确切的说这个文件包含了一个构造器函数,创建了一个真实的controller实例。controller的作用就是将变量和函数暴露给表达式和directives。

除了一个包含controller的javascript文件外,还在html中增加了一个ng-controller directive。这个directive(InvoiceController)告诉angular它负责带该directive的元素和元素下的所有子元素。InvoiceController as invoice这个语法是告诉angular实例化InvoiceController controller并且把它保存在invoice变量在当前scope中。

我们还修改了页面所有的表达式中的变量给他们加上了invoice的前缀(controller实例)。可能会选择的货币在controller中被定义和初始化,并通过ng-repeat的方式添加到了html中。像在controller中定义total函数的那样,我们也能把{‍{ invoice.total(…) }‍}绑定到html中。

我们还给pay按钮通过ng-click directive增加了点击事件,一旦点击就会弹出一个相应的表达式。
这里写图片描述

业务逻辑:Services

现在,InvoiceController包含了这个示例的所有逻辑。当程序需要扩展时,有个比较好的方法是把业务逻辑从页面逻辑controller中抽取出来形成一个service,而且service也可以被其他模块复用,分层思想在angular中的一个体现。需要更改数据的话只需要在service中更改即可。

finance2.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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
};
});

invoice2.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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!");
};
}]);

首先,把convertCurrency函数和currencies数组移到finance2.js文件中,但是controller中怎么才可以访问到finance2中的函数呢?

这时Dependency Injection就派上用场了,Dependency Injection (DI)是一种软件设计模式,主要处理对象和函数的创建并且怎么样获得这些依赖,angular的一切(directives, filters, controllers, services, …)都可以被创建并且通过Dependency Injection连接。在angular中这样的DI容器叫做injector。

为了使用DI,那么就需要一个地方,所有的东西在这里被注册。在angular中,这就是modules干的事。当angular启动时,它会使用在ng-app directive定义的名字的module的配置,并且使用该module需要依赖的所有module的配置。
这里写图片描述
在上面的示例中,template包含了一个directive ng-app=”invoice”,它告诉angular用invoice作为这个应用程序的main module,代码片段angular.module(‘invoice’, [‘finance’])指明invoice module依赖于finace module,angular使用InvoiceController以及currencyConverter service。

InvoiceController怎么样才能拿到currencyConverter函数的引用呢?在angular中其实非常简单,就是在构造函数的参数中定义。injector能按照争取的顺序创建对象,并且可以把之前创建的对象传递到依赖他们的对象的构造函数中。在我妈的例子中,InvoiceController的构造函数有一个叫currencyConverter的参数。这样angularj就知道controller和service之间的依赖关系。

最后要说的是service传递函数以一个数组的方式给controller,这个数组的第一个是controller和service依赖之间约定好的一个name,第二个是service中实际使用的name,如果学过spring 应该很容易理解,这样在代码进行改动时比较容易,只需改动被依赖的代码即可,而且在javascript中也很常用,因为javascript经常被压缩,变成a. b. c. 这样的代码。

文章目录
  1. 1. data binding
  2. 2. 页面逻辑:Controllers
  3. 3. 业务逻辑:Services
|