您的位置:首页 > Web前端 > AngularJS

AngularJS概念概述和第一个使用例子

2014-10-24 13:52 281 查看
点击查看AngularJS系列目录
转载请注明出处:http://www.cnblogs.com/leosx/

概念概述

本节使用一个简单的例子简要介绍了AngularJS的重要组成部分。

概念描述
模板(Template)HTML的附加标记
指令(Directives)通过元素或者客户属性去扩展HTML
模型(Model)用户和界面交互的数据的模型。
上下文(Scope)语境上下文,这样控制器,指令和表达式可以访问它里面的数据。
表达式(Expressions)可以从Scope(上下文)中访问变量和函数。
编译器(Compiler)解析模板和实例化指令和表达式
过滤器(Filter)格式表达式的值以显示给用户
视图(View)用户所看到的(DOM)
数据绑定(Data Binding)模型和视图间同步数据的动作
控制器(Controller)试图(view)背后的业务逻辑
依赖注入(Dependency Injection)创建对象和函数的工厂
注入器(Injector)依赖注入的容器
模块(Module)对应用程序的不同部分,包括控制器,服务器,过滤器,指令进行配置注射器的容器
服务(Service)对于试图可重用的业务逻辑独立的功能部分

第一个例子:数据绑定

在下面的例子中,我们将建立一个表格来计算总价格。

<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和一些新的标记的组合。在AngularJS中,这样的文件称为模板。当AngularJS启动应用程序时,它会使用编译器去分析和处理来自新的标记标识的模板。然后在加载,改造,呈现一个新的DOM到用户视图。

第一个新的标记是指令(directives)。它是HTML元素或者属性的一个特殊的行为。在上面的例子当中,我们使用了 ng-app 属性,这是一个指令,用于自动初始化我们的应用程序。AngularJS还为input元素定义了一些额外的指令,用于增加一些行为来扩展元素。例如:ng-model 指令,用来存储或者更新输入字段的值。

自定义指令访问DOM:在一个AngularJS应用程序中,唯一的一个允许去访问DOM的地方就是指令的范围内(Scope)。这点很重要,因为访问DOM元素是一件很难预测,也很难测试的事情。如果您需要直接访问DOM,你应该写一个自定义的指令去做这件事。

指令章节,我们会去介绍如何自定义。

第二种新的标记是双花括号
{{表达|过滤器}} 
,当编译器遇到这个标记,将其与标记的评估值替换。在模板中的表达式是一个类似于JavaScript的代码段,允许读取和写入变量。请注意,这些变量不是全局变量。就像AngularJS函数和这些变量在一个function函数里面一样,Angular可以去访问。在上面的例子当中,我们的花括号表达式的功能是计算数量和单价,以获得总价格。后面的过滤器使得我们的输出格式为金钱格式(这里加了一个$符号表示是美元为单位的)。在这个例子中,我们可以看到,AngularJS提供了一个绑定:当输入值发生变化,表达式的值会自动重新计算并且去更新DOM与之对应的值。这使用到的概念是双向数据绑定(学过WPF或者Silverlight的同学一定很清楚明白的)。

添加UI逻辑:控制器(controller)

让我们添加更多的逻辑,使我们能够进行不同货币的总价格计算。

第一个文件:invoice1.js

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!");
};
});


第二个文件:index.html

<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>

效果图如下:





和上一个例子相比,有什么改变呢?

首先,增加了一个包含控制器的新的JavaScript文件。更确切地说,该文件包含一个构造函数用于去创建一个真实的Controller控制器的实例。控制器的目的就是为我们的表达式和指令去提供一些变量和方法。

除了增加了新的文件之外,我们还在HTML代码中增加了一个
ng-controller
指令,这个指令就是在告诉AngularJS,去创建一个
InvoiceController
去负责这个元素,以及这个元素下的所有子元素。语法:
ng-controller="InvoiceController as invoice"
是告诉AngularJS去创建一个控制器,并重命名此控制器为invoce,这样下面访问控制器中的变量的时候,就可以使用invoce这个昵称去访问控制器所在的Scope中的变量了,HTML 中,还使用了
ng-repeat
指令去循环指定的元素。也定义了一个方法total (function)方法去计算总价格。

同样,这种结合是很灵活的,即当数据变化时,DOM会自动更新显示变化后的结果。这就省却了我们去修改DOM元素。我们使用了
ng-click
指令去绑定到了按钮点击事件上。这样,当点击按钮的时候,就会触发与
controller
scope
所对应的方法进行执行。

在新的JavaScript文件,我们还在Module中注册了我们的控制器模块。我们将在下一节讨论模块(module),下图显示了所有的东西是如何在Controller里面对应显示出来的。





独立的业务逻辑:服务

眼下,InvoiceController包含我们的例子中的所有逻辑。当我们的逻辑变得复杂之后,我们应该把一些可以独立出来的业务逻辑提出来,放到服务里面去,这样这些独立的业务逻辑块儿就可以重复使用了。之后,我们就可以从网络上加载一些独立的业务逻辑,如装载并调用雅虎的财经API来实现汇率的转换,而我们的控制器不用变。

服务文件:finance2.js

angular.module('finance2', [])
.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

angular.module('invoice2', ['finance2'])
.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!");
};
}]);


HTML文件:index.html

<div ng-app="invoice2" 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>

效果图:





这次又有什么变化呢?

我们新建了一个文件:finance2.js 并且把
convertCurrency
功能移动到了文件当中去。但是我们又如何使得控制器依旧保持着这个功能呢?

这就是依赖注入的用武之地。依赖注入(DI)是软件设计的一部分,它实现了如何创建对象(object)和功能函数(function),以及如何正确找到它们的依赖关系。在Angular中,所有的东西(指令,过滤器,控制器,服务,...)的创建都有使用依赖注入。在Angular中,DI的容器是注入器(injector)

要使用DI,我们首先是要在需要使用的地方进行注册。在Angular中,我们是在模块(modules)中进行注册的。当Angular启动时,它会执行模块的配置(config)然后根据
ng-app
指令开始执行,在执行前,模块会根据配置的名称去加载所有依赖的模块。

在上面的例子当中,包含了一个指令
ng-app="invoice2"
。这是在告诉Angular,应用程序的主模块适用名为:
invoice2
的模块作为主模块。代码段:
angular.module('invoice2', ['finance2'])
指定了
invoice2
的模块依赖于
finance2
模块。也就是说,
InvoiceController
控制器使用了
currencyConverter
服务中的功能。执行到这里Angular知道该应用程序的所有部分了,接下来就是去创建它们了。在上一节我们的控制器使用工厂函数来创建的。在服务方面有多种方式来定义自己的工厂(见服务指南)。在上面的例子中,我们在服务的工厂(factory)中使用了一个函数去返回了一个
currencyConverter
函数功能。





回到最初的问题:如何在InvoiceController控制器中得到一个服务中的currencyConverter功能?在Angular中,这是通过在构造函数中简单地定义参数进行实现的。有了这个,injector能够根据顺序去创建正确的对象,并且在创建前,会先调用创建依赖对象并调用它们的工厂函数。在
InvoiceController
中,有一个
currencyConverter
的参数,有了它,Angular就知道控制器和服务之间的依赖性,并调用与服务实例作为控制器的参数。

无论是上一个例子还是这一个例子,我们都可以看到,我们在
module.controller
函数中,有一个数组,数组首先包含了控制器需要服务相关的名称,它就是在注册所依赖的模块。数组中的最后一项是控制器构造函数。Angular使用此数组语法定义的依赖关系,使得减少了代码污染DI。

访问后台服务

让我们来实现一下我们上面说到的,使用雅虎汇率服务API,去通过网络获得实时的汇率信息。

第一个文件:invoice3.js

angular.module('invoice3', ['finance3'])
.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!");
};
}]);


第二个文件:finance3.js

angular.module('finance3', [])
.factory('currencyConverter', ['$http', function($http) {
var YAHOO_FINANCE_URL_PATTERN =
'//query.yahooapis.com/v1/public/yql?q=select * from '+
'yahoo.finance.xchange where pair in ("PAIRS")&format=json&'+
'env=store://datatables.org/alltableswithkeys&callback=JSON_CALLBACK';
var currencies = ['USD', 'EUR', 'CNY'];
var usdToForeignRates = {};

var convert = function (amount, inCurr, outCurr) {
return amount * usdToForeignRates[outCurr] / usdToForeignRates[inCurr];
};

var refresh = function() {
var url = YAHOO_FINANCE_URL_PATTERN.
replace('PAIRS', 'USD' + currencies.join('","USD'));
return $http.jsonp(url).success(function(data) {
var newUsdToForeignRates = {};
angular.forEach(data.query.results.rate, function(rate) {
var currency = rate.id.substring(3,6);
newUsdToForeignRates[currency] = window.parseFloat(rate.Rate);
});
usdToForeignRates = newUsdToForeignRates;
});
};

refresh();

return {
currencies: currencies,
convert: convert,
refresh: refresh
};
}]);


第三个文件:index.html

<div ng-app="invoice3" 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>

效果图:





点击这里查看示例

这个示例又有什么变化呢?我们的
finance
模块的
currencyConverter
服务,使用了
$http
,
$http
是一个AngularJS内置的用于访问服务器的后端数据的服务。
$http
使用的是
XMLHttpRequest
技术和 JSONP 进行传输.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: