Fork me on GitHub

AngularJS学习笔记总结

介绍

AngularJS是一款由Google公司开发维护的前端MVC框架,其克服了HTML在构建应用上的诸多不足,从而降低了开发成本提升了开发效率。

特点

  • AngularJS有着诸多特性,比如模块化、双向数据绑定、语义化标签、依赖注入等。它与我们之前学习的jQuery是有一定的区别的,jQuery更准确来说只一个类库(类库指的是一系列函数的集合)以DOM做为驱动(核心),而AngularJS则一个框架(诸多类库的集合)以数据做为驱动(核心)。
  • 框架对开发的流程和模式做了约束,开发者遵照约束进行开发,更注重实际业务逻辑,与之类似的框架还有BackBone、KnockoutJS、Vue、React等。

    下载

    1.通过AngularJS官方下载
    2.通过npm下载,npm install angular
    3.通过bower下载,bower install angular

    体验

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>AngularJS 入门指南</title>
    </head>
    <body ng-app>
    <input type="text" ng-model="name">
    <span>hello {{name}}</span>
    <!-- 引入AngularJS框架 -->
    <script src="./libs/angular.min.js"></script>
    </body>
    </html>

MVC

  • MVC是一种开发模式,由模型(Model)、视图(View)、控制器(Controller)3部分构成,采用这种开发模式为合理组织代码提供了方便、降低了代码间的耦合度、功能结构清晰可见。

    • 模型(Model)一般用来处理数据(读取/设置),比如数据库操作
    • 视图(View)一般用来展示数据,比如通过HTML展示
    • 控制器(Controller)一般用做连接模型和视图的桥梁
      MVC示意图
  • MVC更多应用在后端开发程序里,后被引入到前端开发中,由于受到前端技术的限制便有了一些细节的调整,进而出现了很多MVC的衍生版(子集)如MVVM、MVW、MVP、MV*等。

模块化

  • 通过AngularJS构建应用(App)时是以模块化(Module)的方式组织的,即将整个应用划分成若干模块,每个模块都有各自的职责,最终组合成一个整体。

基本结构

angular基本结构

应用(APP)

  • 通过为任一HTML标签添加ng-app属性,可以指定一个应用(App),此标签所包裹的内容都属于应用(App)的一部分。
1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<!-- 将整个文档做为应用 -->
<html lang="en" ng-app="App">
<head>
<meta charset="UTF-8">
<title>AngularJS 入门指南</title>
</head>
<body>

<script src="./libs/angular.min.js"></script>
</body>
</html>

或者

1
2
3
4
5
6
7
8
9
10
11
12
13
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>AngularJS 入门指南</title>
</head>
<body>
<div class="box" ng-app="App">
<!-- 将此盒子包裹内容作为应用 -->
</div>
<script src="./libs/angular.min.js"></script>
</body>
</html>

模块(module)

  • AngularJS提供了一个全局对象angular,在此全局对象下存在若干个方法,其中angular.module方法用来定义一个模块(Module)。
1
2
3
// 第1个参数代表模块名称
// 第2个参数代表依赖其它的模块
var App = angular.module('App', []);

 注:应用(App)其本质也是一个模块

控制器(controller)

  • 控制器(Controller)作为连接模型(Model)和视图(View)的桥梁存在,通过模块实例对象方法controller来定义。
1
2
3
4
5
6
7
8
// App是上述的应用实例
// 通过这个应用实例可以创建控制器
// 第1个参数代表控制器名称
// 第2个参数代表声明依赖并注入
App.controller('DemoController', ['$scope', function ($scope) {
// $scope便是模型(Model)
$scope.somedata = 'Study AngularJS by myself!';
}]);
  • 通过控制器(Controller)将模型(Model)数据展示到对应的视图(View)上,每个视图(View)都可以对应1个或多个控制器(Controller),通过为HTML标签添加ng-controller属性并赋值相应的控制器(Controller)的名称,就确立了关联关系。
1
2
3
4
5
   <!-- ng-controller值为控制器的名称 -->
<div class="box" ng-controller="DemoController">
<!-- 这里可以访问得到$scope(模型)的数据 -->
{{ somedata }}
</div>

完整实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!DOCTYPE html>
<html lang="en" ng-app="App">
<head>
<meta charset="UTF-8">
<title>AngularJS 入门指南</title>
</head>
<body>
<div class="box" ng-controller="DemoController">
{{ somedata }}
</div>
<script src="./libs/angular.min.js"></script>
<script>
var App = angular.module('App', []);
App.controller('DemoController', ['$scope', function($scope) {
$scope.somedata = 'Study AngularJS by myself!';
}])
</script>
</body>
</html>

指令

HTML在构建应用(App)时存在诸多不足之处,AngularJS通过扩展一系列的HTML属性或标签来弥补这些缺陷,所谓指令就是AngularJS自定义的HTML属性或标签,AngularJS自身负责解析这些自定义的属性或标签,AngularJS指令都是以ng-做为前缀的,例如ng-app、ng-controller、ng-repeat等。

1.内置指令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
1.作用域类

- ng-app
- ng-controller

2.内容类

- ng-bind
- ng-model
- 插值语法:{{}}

3.事件类

- ng-click ng-dbclick
- ng-blur ng-focus

4.样式类

- ng-class
- ng-style
- ng-hide/ng-show


5.仿流程控制类:

- ng-if/ng-else
- ng-switch ng-switch-then ng-switch-default
- ng-repeat

2.服务

1.内置服务$http

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
angular.module('s1.app',[])
//angular里面的内置服务
.run(function($http, $rootScope){

// $http.get('data.js')
// .success(function(data){
// console.log(data);
// })
// .error(function(data){
// console.log("error"+data);
// })


//服务的标准用法
$http({
url:'data.js',
data:{},
method:'get'
})
.success(function(data){
console.log(data);
})
.error(function(data){
console.log("error"+data);
})
//或者这样使用
var promise = $http({
url:'data.js',
method:'jsonp',//GET/DELETE/HEAD/JSONP/POST/PUT
data:{},//your data
headers:{
"Content-Type":''//your config
}

});
promise.then(function(resp){
// resp是一个响应的对象
console.log(resp);
},function(resp){
//带有错误信息
console.log(resp);
})
})

2.自定义服务service
service通过构造函数的方式创建service,并返回一个实例化的对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var app = angular.module('s1.app', []);

// 第一个参数:服务的名字
// 第二个参数:服务的构造器
// 使用:在依赖注入时,输入服务的名字,就能拿到“服务对象”。
// 服务对象其实是通过构造函数的方式创建的service
app.service('DemoService', function () {
this.msg = 'hello demo service';
});

app.run(function (DemoService, $rootScope) {
$rootScope.data = {
msg: DemoService.msg
}
})

3.自定义服务factory
factory把service的方法和数据放在一个对象里面,并返回。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var app = angular.module('s1.app', []);

// 第一个参数:服务的名字
// 第二个参数:服务的工厂函数
app.factory('DemoService',function () {

// 服务的工厂函数的返回值,才是服务对象
return {
msg:'this is from factory'
}
});

app.run(function (DemoService, $rootScope) {
$rootScope.data = {
msg: DemoService.msg
}
})

4.自定义服务provider
provider创建一个可通过config配置的service,$get中返回的就是用factory创建service的内容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
 angular.module('s1.app', [])
.provider('DataService', function () {
var host = 'http://localhost:3000';
// 配置对象
return {
setHost: function (newHostUrl) {
host = newHostUrl
},
$get: function () {
// 服务对象
return {
getIndexUrl: function () {
return host + '/index.html'
},
// setHost :function (newHostUrl) {
// host = newHostUrl
// }
}
}

}
})
.config(function (DataService) {
DataService.setHost('http://www.baidu.com')
})
.run(function ($rootScope, DataService) {
// DataService.setHost('http://www.baidu.com');
// // 把设置函数放到服务对象里的方法,没办法使用
// 1这种设置也行,但是不是优化处理,我们想要在使用run函数之前的时候,就能获取到设置的值,而不是调用run的时候再获取,因此要使用config,在真正的程序运行之前,数据就设置好
$rootScope.url = DataService.getIndexUrl();
})

3.过滤器

1.内置过滤器

1
2
3
{{ expression | filter }}
{{expression | filter1 | filter2....}}
{{ expression | filter:argument1:argument2:... }}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<ul ng-controller="DemoController">
<li>{{price|currency:'¥':2}}</li>
<li>{{num|number:2}}</li>
<li>{{low|lowercase}}</li>
<li>{{items|json}}</li>
<li>{{low|limitTo:10|uppercase}}</li>
<li>{{arr|limitTo:-2}}</li>
<li>{{today|date:'yyyy/MM/d EEEE'}}</li>
<li>{{arr|filter:'p'}}</li>
<li>{{students|filter:{age: 12} }}</li>
<!-- <li>{{students|filter:}}</li> -->
<li>{{students|orderBy:'age':true}}</li>
</ul>
<script>
var App = angular.module('App', []);

App.controller('DemoController', ['$scope', function($scope) {

$scope.price = '20.12';

$scope.num = 120.565;

$scope.low = 'My Name Is ItCast';

$scope.items = {
name: 'itcast',
age: 10
}

$scope.arr = ['html', 'css', 'javascrip', 'java', 'php', 'python'];

$scope.today = new Date();

$scope.students = [
{name: '小明', age: 12},
{name: '老王', age: 81},
{name: '小米', age: 6}
]
// JSON.stringify();

}])
</script>
  1. 使用ng提供的内置$filter服务(需要引入进来)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$scope.num = $filter('currency')(12345);//第一个参数过滤器名字,第二个参数是过滤值
$scope.date = $filter('date')(new Date());
//ng内置过滤器
currency 货币处理 {{num | currency : '¥'}}
date 日期格式化 {{date | date : 'yyyy-MM-dd hh:mm:ss EEEE'}} // 年 月 日 时 分 秒 星期
filter 匹配子串 {{ childrenArray | filter : 'a' }} //匹配属性值中含有a的
{{childrenArray | filter : func }} //参数是函数,指定返回age>4的
{{ childrenArray | filter : {name : 'i'} }} //参数是对象,匹配name属性中含有i的

json 格式化json对象 {{ jsonTest | json}}
limitTo 限制数组长度或字符串长度 {{ childrenArray | limitTo : 2 }} //将会显示数组中的前两项
lowercase 小写
uppercase 大写
number 格式化数字 {{ num | number : 2 }}
orderBy 排序 <div>{{ childrenArray | orderBy : 'age' }}</div> //按age属性值进行排序,若是-age,则倒序
  1. 自定义过滤器
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    <div ng-controller="DemoController">
    {{content|capitalize}}
    </div>
    <script src="libs/angular.min.js"></script>
    <script>
    var App = angular.module('App', []);

    App.controller('DemoController', ['$scope', function($scope) {
    $scope.content = 'my name is itcast';
    }]);

    // 定义自定义过滤器
    //参数1:过滤器名字
    //参数2:过滤器执行的程序
    App.filter('capitalize', function () {
    // 下面是固定格式
    return function (input) {
    console.log(input);//my name is itcast
    return input[0].toUpperCase() + input.slice(1);//My name is itcast
    }
    });

    </script>

4.自定义指令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
/ 定义模块
var App = angular.module('App', []);
// 自定义指令
// 第1个参数代表指令名称
// 第2个参数配置指令参数
App.directive('myDirective', function () {
return {
//优先级
priority:10000,
// 自定义指令的类型
restrict: 'EAC',
// 自定义指令模板
template: '<h1>Hello AngularJS!</h1>',
transclude: true,//嵌入
//控制器
controller:function($scope, $element, $attrs){
// $attrs 是元素中的属性,得到的是一个对象
//$element是dom中的元素(标签),得到的是一个数组
var attrMyBind = $attrs.myBind;//获得属性中伪myBind 的值
var result = $scope.$eval(attrMyBind);//将获到的值中的字符串当作变量处理
$element.text(result);//设置元素文本内容

},
link:function (scope, element, attrs) {
// link:链接的意思,链接数据和模板之间的关系
var attrMyBind = attrs.myBind;
var result = scope.$eval(attrMyBind);
element.text(result); //helloform root...
},
replace: true,// 是否替换原始标签
//scope: true, // 自定义指令有自己的作用域
//自定义指令的孤立作用
scope: {// 自定义指令有自己的作用域,隔离作用域
myText:"=" // <单向绑定, =双向绑定, @文本绑定(变量) &函数绑定
},//如果是true时会从父作用域继承并创建一个自己的作用域;默认是false

// .... 还有其它参数
}
});

使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>AngularJS 入门指南</title>
</head>
<body ng-app="App">
<!-- 使用自定义指令 -->
<div my-directive></div>
<script src="./libs/angular.min.js"></script>
<script>
// 定义模块
var App = angular.module('App', []);
// 自定义指令
// 第1个参数代表指令名称
// 第2个参数配置指令参数
App.directive('myDirective', function () {
return {
// 自定义指令的类型
restrict: 'EAC',
// 自定义指令模板
template: '<h1>Hello AngularJS!</h1>',
// 是否替换原始标签
replace: true
// .... 还有其它参数
}
});
</script>
</body>
</html>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 使用自定义指令的嵌入,加上变量,双向绑定
<body ng-app="myApp">
<textarea ng-model="content"></textarea>
<div my-directive title="Kavlez">
<hr>
{{content}}
</div>
</body>
<script type="text/javascript">
var myApp = angular.module('myApp', [])
.directive('myDirective', function() {
return {
restrict: 'EA',
scope: {
title: '@',
content: '='
},
transclude: true,
template: '<h2 class="header">{{ title }}</h2>\
<span class="content" ng-transclude></span>'
};
});
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
使用双向绑定 =
<body ng-app="myApp" ng-init="content='abc'">
<p ng-controller="myController" >
<input type="text" ng-model="content">
<div my-directive="content" ></div>
{{content}}
</p>
</body>
<script type="text/javascript">
var myApp = angular.module('myApp', [])
.directive('myDirective', function($rootScope) {
return {
priority:1000,
restrict: 'A',
replace: true,
scope: {
myDirective: '=',
},
template: '<p>from myDirective:{{myDirective}}</p>'
};
})
.controller('myController',function($scope){
$scope.content = 'from controller';
});
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
//在隔离作用域访问指令外部的作用域的方法还有一种,就是&。
// 我们可以使用&与父级作用域的函数进行绑定,比如下面的例子:

<body ng-app="myApp">
<div ng-controller="myController">
<table border='1'>
<tr>
<td>From</td>
<td><input type="text" ng-model="from"/></td>
</tr>
<tr>
<td>To</td>
<td><input type="text" ng-model="to"/></td>
</tr>
<tr>
<td>Content</td>
<td><textarea cols="30" rows="10" ng-model="content"></textarea></td>
</tr>
<tr>
<td>Preview:</td>
<td><div scope-example to="to" on-send="sendMail(content)" from="from" /></td>
</tr>
</table>
</div>
</div>

</body>
<script type="text/javascript">
var myApp = angular.module('myApp', [])
.controller('myController',function($scope){
$scope.sendMail=function(content){
console.log('content is:::'+content);
}
})
.directive('scopeExample',function(){
return{
restrict:'EA',
scope: {
to: '=',
from: '=' ,
send: '&onSend'
},
template:'<div>From:{{from}}<br>\
To:{{to}}<br>\
<button ng-click="send()">Send</button>\
</div>'
}
})
</script>

5. ng-transclude

如果页面中书写了这个指令说明是可以嵌入内部元素的

6. $compile

编译一段HTML字符串或者DOM的模板,产生一个将scope和模板连接到一起的函数。
$compile(element,transclude,maxPriority);
element:将要被编译和插入模板的元素或者HTML字符串。
transclude:指令内有效的函数。Function(angular.Scope,cloneAttachFn=)
maxPriority:只有在指令比给定的优先级低时应用。只影响根元素,不影响子元素。
返回:
一个用于绑定HTML模板到一个作用域的连接函数。

7. angular中的http拦截器Interceptors的实现

在angularJs中增加了一个全局的http请求统一做出处理的api–interceptors
Interceptors有两个处理时机, 分别是:
(1) 其它程序代码执行HTTP请求之后,在实际从浏览器发出请求之前,即处理请求
(2) 得到请求的响应之后,在交给其它程序代码处理之前,即处理请求的响应
其引用场景包括:
(1) 全局处理错误
(2) 统一进行身份验证一类的处理
(3) 对所有发出去的请求进行预处理
(4) 对所有收到的响应进行预处理等等

数据绑定

  • AngularJS是以数据做为驱动的MVC框架,所有模型(Model)里的数据经过控制器(Controller)展示到视图(View)中。
  • 所谓数据绑定指的就是将模型(Model)中的数据与相应的视图(View)进行关联,分别有单向绑定和双向绑定两种方式。

1.单项数据绑定

  • 单向数据绑定是指将模型(Model)数据,按着写好的视图(View)模板生成HTML标签,然后追加到DOM中显示,如之前所学的artTemplate 模板引擎的工作方式。
    单项数据绑定

如上图所示,只能模型(Model)数据向视图(View)传递。

2.双向数据绑定

  • 双向绑定则可以实现模型(Model)数据和视图(View)模板的双向传递,如下图所示

双向数据绑定

3.相关指令

1
2
在AngularJS通过\{\{\}\}和ng-bind指令来实现模型(Model)数据向视图模板(View)的绑定,模型数据通过一个内置服务$scope来提供,这个$scope是一个对象,通过为这个对象添加属性或者方法便可以在相应的视图(View)模板里访问得到。
注:\{\{\}\}是ng-bind的简写形式,其区别在于通过\{\{\}\}绑定数据时会有“闪烁”现象,添加ng-cloak也可以解决“闪烁”现象,通过ng-bind-template可以绑定多个数据。

作用域

  通常AngularJS中应用(App)是由若干个视图(View)组合成而成的,而视图(View)又都是HTML元素,并且HTML元素是可以互相嵌套的,另一方面视图都隶属于某个控制器(Controller),进而控制器之间也必然会产生嵌套关系。
  每个控制器(Controller)又都对应一个模型(Model)也就是$scope对象,不同层级控制器(Controller)下的$scope便产生了作用域。

1.根作用域

  一个AngularJS的应用(App)在启动时会自动创建一个根作用域$rootScope,这个根作用域在整个应用范围(ng-app所在标签以内)都是可以被访问到的。

2.子作用域

  通过ng-controller指令可以创建一个子作用域,新建的作用域可以访问其父作用域的数据。

angular依赖注入的原理解析

通过构造函数的参数的名字来推断依赖的服务名称,通过toString()来找到这个定义的function对应的字符串,然后利用正则表达式去解析其中的参数,再去依赖映射取到对应的依赖,实例化之后传入。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function controller(callback){
var scope = '小明';
var age = 23;
//判断用户传入参数的名字
var str = callback.toString();
var arr = str.split(/\(|\)/);
var arrName = arr[1];
if(arrName=='scope'){
callback(scope);
}else if(arrName=='age'){
callback(age)
}
}
//依赖注入
controller(function(scope){
console.log(scope);//小明
})

-------------本文结束感谢您的阅读-------------