title: 看书总结之AngularJS权威教程
第一章 初始AngularJS
1.浏览器是如何获取网页的
当你打开一个浏览器,并在地址栏输入URL后,浏览器会询问DNS服务器该URL对应的IP地址是什么。如果DNS知道IP是什么就会将其结果返回,否则它会将请求转发给其他的DNS服务器,直到在某一台DNS服务器上找到对应的IP地址记录,在终端输入下列指令,可以观察DNS服务器的响应内容:
$ dig baidu.com
DNS服务器返回了你要访问的计算机的IP地址后,它就会向这个IP地址对应的计算机请求你要访问的页面。现在,计算机已经知道了在哪个IP地址可以访问到http://wwwbaidu.com,它会向百度的服务器
请求显示这个页面所需的HTML。当远程服务器把HTML文档发送回来后,浏览器会对文档进行渲染。渲染就是通过一系列操
作,使HTML页面按照设计之初的既定方式显示。
2.浏览器是什么
目前市场上有很多不同品牌的浏览器,常见的有Chrome、Safari、Firefox和IE。它们的核心
功能基本上都是相同的:获取网页,并将它显示给用户。
浏览器获取页面对应的HTML文本,将其解析为一个在浏览器内部使用的结构,对页面的内
容进行布局,并在内容显示到屏幕上之前加上样式,所有这些工作都是在浏览器内部进行的。
作为Web开发人员,我们的工作是构造网页的结构和内容,这样浏览器才能将它们转化成对
用户来说比较美观的形式。
使用AngularJS,不仅可以构建页面的结构,而且可以构建用户和Web应用之间的交互
3.Angular是什么
官方文档:完全使用Javascript编写的客户端技术,同其他历史悠久的WEB技术配合使用,使Web应用开发比以往更简单、更快捷
AngularJS主要用于构建单页面Web应用。它通过增加开发人员和常见Web应用开发任务之间
的抽象级别,使构建交互式的现代Web应用变得更加简单
第二章 数据绑定和第一个AngularJS Web应用
1.AngularJS中的数据绑定
- AngularJS采用了完全不同的解决方案。他创建实时模板来代替视图,而不是将数据合并进模板之后更新DOM。任何一个独立视图组件中的值都是动态替换的
2.简单的数据绑定
function MyController($scope, $timeout) {
var updateClock = function() {
$scope.clock = new Date();
$timeout(function() {
updateClock();
}, 1000);
};
updateClock();
};
3.数据绑定的最佳实践
由于JavaScript自身的特点,以及它在传递值和引用时的不同处理方式,通常认为,在视图中
通过对象的属性而非对象本身来进行引用绑定,是Angular中的最佳实践
function MyController($scope) {
$scope.clock = {
now: new Date()
};
var updateClock = function() {
$scope.clock.now = new Date()
};
setInterval(function() {
$scope.$apply(updateClock);
}, 1000);
updateClock();
};
第三章 模块
模块能带来的好处
- 保持全局命名空间的清洁;
- 编写测试代码更容易,并能保持其清洁,以便更容易找到互相隔离的功能;
- 易于在不同应用间复用代码;
- 使应用能够以任意顺序加载代码的各个部分。
angular.module()
方法声明模块,这个方法接受两个参数
一个是模块名称,另一个是依赖列表
angular.module("myApp", []); 相当于AngularJS模块的setter方法,是用来定义模块的;
angular.module("myApp") 相当于AngularJS模块中的getter方法,用来获取对模块的引用。
name(字符串)
name模块的名称,字符串变量
requires(字符串数组)
requires包含了一个字符串变量组成的列表,每个元素都是一个模块名称,本模块依赖于这些模块,依赖需要在本模块加载之前由注入器进行预加载。
第四章 作用域
应用的作用域是和应用的数据模型相关联的,同时作用域也是表达式执行上下文。$scope对象时定义应用业务逻辑、控制器方法和视图属性的地方。
作用域提供了监视数据模型变化的能力。它允许开发者使用其中的apply机制,将数据模型的变化在整个应用范围内进行通知。我们在作用域的上下文中定义和执行表达式,同时它也是将事件通知给另一个控制器和应用其他部分的中介。
1.视图和$scope的世界
- AngularJS启动并生成视图时,会将根ng-app元素同$rootscope进行绑定。$rootscope是所有对象的最上层。
- $rootScope是AngularJS中最接近全局作用域的对象。在$rootScope上附加太多业务逻并不是好主意,这与污染JavaScript的全局作用域是一样的。
- $scope对象就是一个普通的JavaScript对象,我们可以在其上随意修改或添加属性。
- $scope对象在AngularJS中充当数据模型,但与传统的数据模型不一样,$scope并不负责处理和操作数据,它只是视图和HTML之间的桥梁,它是视图和控制器之间的胶水
- $scope的所有属性,都可以自动被视图访问到
2.就是HTML而已
我们可以在AngularJS应用的模板中使用多种标记
- 指令:将DOM元素增强为可复用的DOM组件的属性或元素。
- 值绑定:模板语法{{ }}可以将表达式绑定到视图上。
- 过滤器:可以在视图中使用的函数,用来进行格式化。
- 表单控件:用来检验用户输入的控件。
3.作用域的作用
- 提供观察者以监视数据模型的变化;
- 可以将数据模型的变化通知给整个应用,甚至是系统外的组件;
- 可以进行嵌套,隔离业务功能和数据;
- 给表达式提供运算时所需的执行环境。
作用域包含了渲染视图时所需要的功能和数据,它是所有视图的唯一源头。可以将作用域理解成视图模型。
下面看一个例子吧:
视图中:
<div ng-app="myApp">
<h1>Hello {{ name }}</h1>
</div>
在$rootScope中设置了一个name变量并在视图中引用了它:
angular.module('myApp', [])
.run(function($rootScope) {
$rootScope.name = "World";
});
我们可以不讲变量设置在$rootscope上,而是用控制器显式创建一个隔离的子$scope对象,把它设置到这个子对象上。
例子如下:
<div ng-app="myApp">
<div ng-controller="MyController">
<h1>Hello {{ name }}</h1>
</div>
</div>
angular.module("myApp", [])
.controller('MyController',
function($scope) {
$scope.name = "Ari";
});
ng-controller指令为这个DOM元素创建了一个新的$scope对象,并将它嵌套在$rootScope中
4.$scope的生命周期
- 当Angular关心的事件发生在浏览器中时,比如用户在通过ng-model属性监控的输入字段中输入,或者带有ng-click属性的按钮被点击时,Angular的事件循环都会启动。这个事件将在Angular执行上下文中处理。
- 每当事件被处理时,$scope就会对定义的表达式求值。此时事件循环会启动,并且Angular应用会监控应用程序内的所有对象,脏值检测循环也会运行。
$scope对象的生命周期处理有四个不同阶段
1.创建
在创建控制器或指令时,AngularJS会用$injector创建一个新的作用域,并在这个新建的控制器或指令运行时将作用域传递进去
2.链接
当Angular开始运行时,所有的$scope对象都会附加或者链接到视图中。所有创建$scope对象的函数也会将自身附加到视图中。这些作用域将会注册当Angular应用上下文中发生变化时需要运行的函数。
这些函数被称为$watch函数,Angular通过这些函数获知何时启动事件循环
3.更新
当事件循环运行时,它通常执行在顶层$scope对象上(被称作$rootScope),每个子作用域都执行自己的脏值检测。每个监控函数都会检查变化。如果检测到任意变化,$scope对象就会触发指定的回调函数
4.销毁
当一个$scope在视图中不再需要时,这个作用域将会清理和销毁自己
尽管永远不会需要清理作用域(因为Angular会为你处理),但是知道是谁创建了这个作用域还是有用的,因为你可以使用这个$scope上叫做$destory()的方法来清理这个作用域
第五章 控制器
控制器在AngularJS中的作用是增强视图
AngularJS中的控制器是一个函数,用来向视图的作用域中添加额外的功能。我们用它来给作用域对象设置初始状态,并添加自定义行为。
当我们在页面上创建一个新的控制器时,AngularJS会生成并传递一个新的$scope给这个控制器。可以在这个控制器里初始化$scope。由于AngularJS会负责处理控制器的实例化过程,我们只需编写构造函数即可。
展示控制器初始化:
function FirstController($scope) {
$scope.message = "hello";
}
在创建作用域时,我们最好不要再全局作用域中创建函数,因为会污染全局明明空间,合理的方式是创建一个模块,然后在模块中创建控制器
var app = angular.module('app', []);
app.controller('FirstController', function($scope) {
$scope.message = "hello";
});
只需创建控制器作用域中的函数,就能创建可以在视图中使用的自定义操作,AngularJS允许我们在视图中像调用普通数据一样调用$scope上的函数。
控制器可以将与一个独立视图相关的业务逻辑封装在一个独立的容器中。尽可能地精简控制器是很好的做法。作为AngularJS开发者,使用依赖注入来访问服务可以实现这个目的
AngularJS同其他JavaScript框架最主要的一个区别就是,控制器并不适合用来执行DOM操作、格式化或数据操作,以及除存储数据模型之外的状态维护操作。它只是视图和$scope之间的桥梁。
AngularJS允许在$scope上设置包括对象在内的任何类型的数据,并且在视图中还可以展示对象的属性
在拥有ng-controller这个属性的元素的任何子元素都可以访问定义在controller里面的对象,因为它是定义在$scope上的
$scope对象用来从数据模型向视图传递信息。同时,它也可以用来设置事
件监听器,同应用的其他部分进行交互,以及创建与应用相关的特定业务逻辑
app.controller('MyController', function($scope) {
$scope.person = {
name: 'Ari Lerner'
};
});
<div ng-app="myApp">
<div ng-controller="MyController">
<h1>{{ person }}</h1>
and their name:
<h2>{{ person.name }}</h2>
</div>
</div>
控制器的嵌套
AngularJS应用的任何一个部分,无论它渲染在哪个上下文中,都有父级作用域存在。对于ng-app所处的层级来讲,它的父级作用域就是$rootScope
有一个例外:在指令内部创建的作用域被称作孤立作用域。
除了孤立作用域外,所有的作用域都通过原型继承而来,也就是说它们都可以访问父级作用域
默认情况下,AngularJS在当前作用域中无法找到某个属性时,便会在父级作用域中进行查找。如果AngularJS找不到对应的属性,会顺着父级作用域一直向上寻找,直到抵达$rootScope为止。如果在$rootScope中也找不到,程序会继续运行,但视图无法更新
看下例子再理解吧:
app.controller('ParentController', function($scope) {
$scope.person = {greeted: false};
});
app.controller('ChildController', function($scope) {
$scope.sayHello = function() {
$scope.person.name = 'Ari Lerner';
};
});
<div ng-controller="ParentController">
<div ng-controller="ChildController">
<a ng-click="sayHello()">Say hello</a>
</div>
{{ person }}
</div>
第六章 表达式
表达式和eval(javascript)非常相似,但是由于表达式由AngularJS来处理,它们有以下显著不同的特性:
- 所有的表达式都在其所属的作用域内部执行,并有访问本地$scope的权限;
- 如果表达式发生了TypeError和ReferenceError并不会抛出异常;
- 不允许使用任何流程控制功能(条件控制,例如if/eles);
- 可以接受过滤器和过滤器链。
对表达式进行的任何操作,都会在其所属的作用域内部执行,因此可以在表达式内部调用那些限制在此作用域内的变量,并进行循环、函数调用、将变量应用到数学表达式中等操作。
解析AngularJS表达式
尽管AngularJS会在运行$digest循环的过程中自动解析表达式,但有时手动解析表达式也是非常有用的。
AngularJS通过$parse这个内部服务来进行表达式的运算,这个服务能够访问当前所处的作用域。这个过程允许我们访问定义在$scope上的原始JavaScript数据和函数
将$parse服务注入到控制器中,然后调用它就可以实现手动解析表达式
下面举个例子:
<div ng-controller="MyController">
<input ng-model="expr"
type="text"
placeholder="Enter an expression" />
<h2>{{ parseValue }}</h2>
</div>
我们可以在MyController中给expr这个表达式设置一个$watch并解析它
angular.module("myApp", [])
.controller('MyController',
function($scope,$parse) {
$scope.$watch('expr', function(newVal, oldVal, scope) {
if (newVal !== oldVal) {
// 用该表达式设置parseFun
var parseFun = $parse(newVal);
// 获取经过解析后表达式的值
$scope.parsedValue = parseFun(scope);
}
});
});
2.插值字符串**(理解)
在AngularJS中,我们的确有手动运行模板编译的能力。例如,插值允许基于作用域上的某个条件实时更新文本字符串。
要在字符串模板中做插值操作,需要在你的对象中注入$interpolate服务。
我们将它注入到一个控制器中
angular.module('myApp', [])
.controller('MyController',
function($scope, $interpolate) {
// 我们同时拥有访问$scope和$interpolate服务的权限
});
$interpolate服务是一个可以接受三个参数的函数。
- text(字符串)::一个包含字符插值标记的字符串(必须)
- mustHaveExpression(布尔型):如果将这个参数设为true,当传入的字符串中不含有表达式时会返回null
- trustedContext(字符串):AngularJS会对已经进行过字符插值操作的字符串通过$sec.getTrusted()方法进行严格的上下文转义
$interpolate服务返回一个函数,用来在特定的上下文中运算表达式。
<div ng-controller="MyController">
<input ng-model="to"
type="email"
placeholder="Recipient" />
<textarea ng-model="emailBody"></textarea>
<pre>{{ previewText }}</pre>
</div>
由于控制器内部设置了一个需要每次变化都重新进行字符插值的自定义输入字段,因此需要设置一个$watch来监听数据的变化
angular.module('myApp', [])
.controller('MyController', function($scope, $interpolate) {
// 设置监听
$scope.$watch('emailBody', function(body) {
if (body) {
var template = $interpolate(body);
$scope.previewText =
template({to: $scope.to});
}
};
});
现在,在{{ previewText }}内部的文本中可以将{{ to }}当做一个变量来使用,并对文本的变化进行实时更新
用startSymbol()方法可以修改标识开始的符号。这个方法接受一个参数。
- value(字符型):开始符号的值。
用endSymbol()方法可以修改标识结束的符号。这个方法也接受一个参数。
- value(字符型): 结束符号的值。
如果要修改这两个符号的设置,需要在创建新模块时将$interpolateProvider注入进去
//重新配置
angular.module('emailParser', [])
.config(['$interpolateProvider', function($interpolateProvider) {
$interpolateProvider.startSymbol('__');
$interpolateProvider.endSymbol('__');
}])
//定义一个服务
.factory('EmailParser', ['$interpolate', function($interpolate) {
// 处理解析的服务
return {
parse: function(text, context) {
var template = $interpolate(text);
return template(context);
}
};
}]);
我们已经创建了一个模块,可以将它注入到应用中,并在邮件正文中运行这个邮件解析器:
//在应用中运用
angular.module('myApp', ['emailParser'])
.controller('MyController', ['$scope', 'EmailParser',
function($scope, EmailParser) {
// 设置监听
$scope.$watch('emailBody', function(body) {
if (body) {
$scope.previewText = EmailParser.parse(body, {
to: $scope.to
});
}
});
}]);
<div id="emailEditor">
<input ng-model="to"
type="email"
placeholder="Recipient" />
<textarea ng-model="emailBody"></textarea>
</div>
<div id="emailPreview">
<pre>__ previewText __</pre>
</div>
第七章 过滤器
过滤器用来格式化需要展示给用户的数据。
在HTML中的模板绑定符号{{}}内通过|符号来调用过滤器。
{{ name | uppercase }}
在JavaScript代码中可以通过$filter来调用过滤器。
app.controller('DemoController', ['$scope', '$filter',
function($scope, $filter) {
$scope.name = $filter('lowercase')('Ari');
}]);
以HTML的形式使用过滤器时,如果需要传递参数给过滤器,只要在过滤器名字后面加冒号即可。如果有多个参数,可以在每个参数后面都加入冒号
{{ 123.456789 | number:2 }}
可以用|符号作为分割符来同时使用多个过滤器
AngularJS提供的内置过滤器
currency
currecy过滤器可以将一个数值格式化为货币格式。用{{ 123 | currency }}来将123转化成货币格式
currecy过滤器允许我们自己设置货币符
date
date过滤器可以将日期格式化成需要的格式。AngularJS中内置了几种日期格式,如果没有指定使用任何格式,默认会采用mediumDate格式
{{ today | date:'medium' }} <!-- Aug 09, 2013 12:09:02 PM -->
{{ today | date:'short' }} <!-- 8/9/1312:09PM -->
{{ today | date:'fullDate' }} <!-- Thursday, August 09, 2013 -->
{{ today | date:'longDate' }} <!-- August 09, 2013 -->
{{ today | date:'mediumDate' }}<!-- Aug 09, 2013 -->
{{ today | date:'shortDate' }} <!-- 8/9/13 -->
{{ today | date:'mediumTime' }}<!-- 12:09:02 PM -->
{{ today | date:'shortTime' }} <!-- 12:09 PM -->
年份格式化
四位年份:{{ today | date:'yyyy' }} <!-- 2013 -->
两位年份:{{ today | date:'yy' }} <!-- 13 -->
一位年份:{{ today | date:'y' }} <!-- 2013 -->
月份格式化
英文月份:{{ today | date:'MMMM' }} <!-- August -->
英文月份简写:{{ today | date:'MMM' }} <!-- Aug -->
数字月份:{{ today |date:'MM' }} <!-- 08 -->
一年中的第几个月份:{{ today |date:'M' }} <!-- 8 -->
日期格式化
数字日期:{{ today|date:'dd' }} <!-- 09 -->
一个月中的第几天:{{ today | date:'d' }} <!-- 9 -->
英文星期:{{ today | date:'EEEE' }} <!-- Thursday -->
英文星期简写:{{ today | date:'EEE' }} <!-- Thu -->
小时格式化
24小时制数字小时:{{today|date:'HH'}} <!--00-->
一天中的第几个小时:{{today|date:'H'}} <!--0-->
12小时制数字小时:{{today|date:'hh'}} <!--12-->
上午或下午的第几个小时:{{today|date:'h'}} <!--12-->
分钟格式化
数字分钟数:{{ today | date:'mm' }} <!-- 09 -->
一个小时中的第几分钟:{{ today | date:'m' }} <!-- 9 -->
秒数格式化
数字秒数:{{ today | date:'ss' }} <!-- 02 -->
一分钟内的第几秒:{{ today | date:'s' }} <!-- 2 -->
毫秒数:{{ today | date:'.sss' }} <!-- .995 -->
字符格式化
上下午标识:{{ today | date:'a' }} <!-- AM -->
四位时区标识:{{ today | date:'Z' }} <!--- 0700 -->
下面是一些自定义日期格式的示例:
{{ today | date:'MMMd, y' }} <!-- Aug9, 2013 -->
{{ today | date:'EEEE, d, M' }} <!-- Thursday, 9, 8-->
{{ today | date:'hh:mm:ss.sss' }} <!-- 12:09:02.995 -->
filter
filter过滤器可以从给定数组中选择一个子集,并将其生成一个新数组返回。这个过滤器通常用来过滤需要进行展示的元素。例如,在客户端搜索时,可以从一个数组中立刻过滤出所需要的结果。
这个过滤器的第一个参数可以是字符串,对象或是一个用来从数组中选择元素的函数。
json
limitTO
lowercase
number
orderBy
uppercase