AngularJS概念概述和第一个使用例子
点击查看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 进行传输.
AngularJS概念概述和第一个使用例子的更多相关文章
- 不用搭环境的10分钟AngularJS指令简易入门01(含例子)
不用搭环境的10分钟AngularJS指令简易入门01(含例子) `#不用搭环境系列AngularJS教程01,前端新手也可以轻松入坑~阅读本文大概需要10分钟~` AngularJS的指令是一大特色 ...
- 按照鬼哥学so变化,四,第一章的例子
跟随鬼哥伦比亚科学so变化,四.第一章的例子 图纸/文化 听鬼哥说故事 ---------------------------------------------切割线--------------- ...
- 从源码编译安装PCL并运行第一个小例子
如何通过源码编译方式安装PCL 对于很多想学习PCL的同学而言,往往会被如何安装困扰很长时间.我就是这其中的一员,为了不让大家在安装问题上浪费太多时间,我决心写下这篇小小的随笔,希望对大家有所帮助. ...
- Angular开发者指南(二)概念概述
template(模板):带有附加标记的模板HTML directives(指令):使用自定义属性和元素扩展HTML model(模型):用户在视图中显示的数据,并与用户进行交互 scope(作用域) ...
- 针对angularjs下拉菜单第一个为空白问题处理
angularjs 的select的option是通过循环造成的,循环的方式可能有 ng-option 或 者 <option ng-repeat></option ...
- 《hadoop权威指南》关于hive的第一个小例子的演示
本文是<hadoop权威指南>关于hive的小例子,通过这个例子可以很好地看出来hive是个什么东西. 前提是已经配置好hive的远程连接版本的环境,我是用了MYSQL数据库保存元数据. ...
- springmvc入门的第一个小例子
今天我们探讨一下springmvc,由于是初学,所以简单的了解一下 springmvc的流程,后续会持续更新... 由一个小例子来简单的了解一下 springmvc springmvc是spring框 ...
- NodeJS系列~第一个小例子,实现了request.querystring功能
返回目录 百度百科上: Node.js是一套用来编写高性能网络服务器的JavaScript工具包,一系列的变化由此开始,在Node中,Http是首要的.Node为创建http服务器作了优化,所以在网上 ...
- Camel In Action 阅读笔记 第一部分概述 + 第一章概述 认识Camel
第一部分: 最开始的一小步 Apache Camel 是一个开源集成框架,其目的是让系统集成变得更加简便,在本书的第一章中,我们会为您介绍它并向您展示它是如何在大型企业应用中做好集成工作.您也会了解到 ...
随机推荐
- Andrew Ng机器学习课程笔记--week7(SVM)
本周主要学习SVM 一. 内容概要 Large Margin Classification Optimization Objective(优化Objective(损失函数)) Large Margin ...
- mongodb菜鸟整理
一,mongodb的安装与连接 从官网下载后,解压或者安装到某个目录下 1 首先需要自己创建一个db文件夹 ,用于存放数据库的数据 然后还需要创建一个log文件夹,里面需要自己创建一个mongodb ...
- Python学习笔记4
根据文件类型选择文件 文件 s s.split('.')[1] 即为文件后缀名,据此判断 输出执行后结果到指定文件 os.system('E:\\Learning\\python\\test_case ...
- 用xml画水平虚线和竖直虚线.md
1.画水平虚线 直接建一个shape,设置stroke属性就行了,再将这个属性直接作为background的drawable属性引入就行了 注意在4.0以上的真机加一句 <?xml versio ...
- 使用 qemu 搭建内核开发环境
本文主要介绍在 MacOS 上使用 qemu 搭建 Linux Kernel 的开发环境.(在开始之前需要注意的是,本文中的 Linux 开发环境是一个远程服务器,而 qemu 被安装在本地的 Mac ...
- java面向对象(二)之继承
继承 介绍 继承是从已有的类中派生出新的类,新的类能吸收已有类的数据属性和行为,并能扩展新的能力.继承即常说的is-a关系.子类继承父类的特征和行为,使得子类具有父类的各种属性和方法.或子类从父类继承 ...
- Visual Studio2017 远程调试 Remote Debugger
前言 大家在使用vs打包后的文件部署到服务器后,有时候我们需要对线网的后台进行调试.但是它不像在VS中.这个时候我们该怎么调试呢? 微软想到了这一点,他们在 VS 中给我们提供了一个功能: Remot ...
- 那么 Appium 到底是怎么工作的呢?
因为官网文档写的没有梯度,作为新手的我花了好几个小时硬是没看明白它是怎么工作的. 网上教程也基本都是翻译,所以结构很复杂.和其他技术耦合度很高,且没有说明. 我自己总结了一份超简单 Appium 自动 ...
- HTML canvas 笑脸
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- 【Beta】阶段 第一次Daily Scrum Meeting
每日任务 1.本次会议为第一次 Meeting会议: 2.本次会议在周一下午16:40,课间休息时间在禹州楼召开,召开本次会议为10分钟. 一.今日站立式会议照片 二.每个人的工作 (有work it ...