AngularJS 框架

写在最前:由于 ng 的表达式和博客有冲突,所以除了代码块之外所有的大括号经过了 \ 转义!

Angular 介绍

什么是框架和库

库是由开发人员主动使用库里面提供的 API,完成代码功能逻辑

框架里面提供了各种各样的库,这些库可以调用使用,也可以由框架去调用使用

什么是 AngularJS

  • 一款非常优秀的前端高级 JavaScript 框架
  • 可以轻松构建 SPA 应用程序
  • 通过 指令 扩展了 HTML,通过 表达式 绑定数据到 HTML
  • 最大程度上解放了 DOM 操作
  • 构建更加动感的 HTML 应用程序

AngularJS是为了克服HTML在构建应用上的不足而设计的。AngularJS有着诸多特性,最为核心的是:

  • MVC
  • 模块化
  • 自动化双向数据绑定
  • 语义化标签、依赖注入等等

为什么使用 Angular

以前我们是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>传统页面操作数据操作方式</title>
</head>
<body>
<input id="txt_value" type="number">
<input id="btn_add" type="button" value="增加">
<script>
(function(window, document) {
var txt = document.querySelector('#txt_value');
var btn = document.querySelector('#btn_add');
btn.addEventListener('click', function(e) {
var now = txt.value - 0;
now = now + 1;
txt.value = now;
});
})(window, document);
</script>
</body>
</html>

以后将会是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>使用AngularJS实现自增功能</title>
</head>
<body ng-app>
<input type="number" ng-model="value">
<input type="button" ng-click="value=value+1" value="增加">
<script src="../bower_components/angular/angular.js"></script>
</body>
</html>

AngularJS 优缺点

优点:

  1. AngularJS 模板功能强大丰富,自带了极其丰富的angular指令。
  2. AngularJS 是完全可扩展的,与其他库的兼容效果很好,每一个功能可以修改或更换,以满足开发者独特的开发流程和功能的需求。
  3. AngularJS 是一个比较完善的前端MVC框架,包含服务,模板,数据双向绑定,模块化,路由,过滤器,依赖注入等所有功能;
  4. AngularJS 是互联网巨人谷歌开发,这也意味着他有一个坚实的基础和社区支持。

缺点:

  1. AngularJS 强约束导致学习成本较高,对前端不友好。但遵守 AngularJS 的约定时,生产力会很高,对 后台服务器开发程序员友好。
  2. AngularJS 不利于 SEO,因为所有内容都是动态获取并渲染生成的,搜索引擎没法爬取。
  3. AngularJS 作为 MVVM 框架,因为实现了数据的双向绑定,对于大数组、复杂对象会存在性能问题。

AngularJS 使用场景

  • 单页面应用程序
  • 复杂的后台管理系统
    • CRUD(增加 Create、查询 Retrieve、更新 Update、删除 Delete)
    • 繁杂的 DOM 操作处理的页面

Angular 是一个类 MVC 类结构的 JavaScript 框架,建议构建 CRUD 类型应用的时候使用它,而对于那些图形编辑、游戏开发等应用,使用 Angular 就不如调用其它 JavaScript 类库方便,如 jQuery。

AngularJS资源

SPA 单页面应用程序

SPA全称:Single Page Application,单页面应用程序。

所谓的单页应用:其实就是利用 hash 做网页内部局部内容的替换

(1). 为什么不适用传统的路径?

原因是传统的路径会默认发同步请求跳转

(2). 为什么 hash 中的路径都是以 / 开头

原因是为了区分普通的 hash

传统的网站模型:多页面应用模型

SPA 网站模型

  • 网易云音乐实例解析

锚点:网页内部定位

  • id
  • a.name

利用锚点改变网页内容

  • window对象的 hashchange 事件
  • window.location 拿到锚点的内容
  • 根据不同的 hash 显示不同的内容

单页应用的好处

  • 提高了整个应用程序的响应速度、增加了用户体验
  • 重用资源
  • 方便统一控制和代码重用

如何在网页中解析 URL 地址

Angular 的应用

关于版本

安装

  • github
    • https://github.com/angular/angular.js/releases
  • CDN
    • https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js
  • bower
    • bower install angular#1.5.8
  • npm
    • npm install angular@1.5.8

第一个 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>ng - HelloHiraku</title>
</head>
<body ng-app ng-init="name='World'">
Name: <input type="text" ng-model="name">
<hr>
<h1>Hello {{name}}!</h1>
<script src="angular.js"></script>
</body>
</html>

代码解析

  • 当网页加载完毕,AngularJS 自动开始执行
  • HTML 页面中 ng-xxx 的属性称之为指令(Directive)
  • ng-app 指令告诉 AngularJS ,<body> 元素是 AngularJS 应用程序管理的边界
  • ng-init 指令初始化 AngularJS 应用程序变量
  • ng-model 指令把文本框的 value 值绑定到变量 name
  • \{\{ name \}\} 表达式就是把应用程序变量 name 绑定到某个元素的 innerHTML

ng 使用过程

(0). 引包

(1). 在 body 上添加一个属性:ng-app

(2). 在 body 中写一个 <h1>\{\{'Hello ' + 'World!'\}\}</h1>

解析过程:

  1. 浏览器从上到下依次解析 DOM 文档
  2. 当浏览器解析到 body 上有一个 ng-app 属性的时候,浏览器对于不识别的属性会选择忽略
  3. 当浏览器解析到 <h1>\{\{'Hello ' + 'World!'\}\}</h1> ,浏览器无法识别里面的双花括号以及里面的内容,浏览器会把它当成普通的字符串进行渲染
  4. 当浏览西发现 script 标签指定的 angular.js 引用文件的时候,发送请求下载该文件
  5. 当 angular.js 程序下载成功之后,开始自动执行
  6. ng 自动找到网页中具有 ng-app 属性的元素,然后开始解析该元素内部所有能被 ng 所识别的元素,也就是说 ng-app 在这里就充当了 ng 应用程序启动的入口标识,同时也是 ng 应用程序的管理边界
  7. ng 找到入口标识之后,开始解析该入口标识中所有的自己能识别的内容

例如,这里使用了一个 \{\{\}\} 表达式,\{\{\}\} 在 ng 中被称作花括号插值表达式。

AngularJS 表达式

  • AngularJS 表达式写在双大括号内:\{\{ expression \}\}
  • AngularJS 表达式把数据绑定到 HTML,与 ng-bind 指令基本一致
  • AngularJS 将在表达式书写的位置”输出”数据
    • 数字
    • 字符串
    • 对象
    • 数组
  • AngularJS 表达式 很像 JavaScript 表达式:它们可以包含字符串、操作符和变量
    • 与 JavaScript 表达式不同,AngularJS 表达式可以写在 HTML 中
    • 与 JavaScript 表达式不同,AngularJS 表达式不支持条件判断,循环及异常
    • 与 JavaScript 表达式不同,AngularJS 表达式支持过滤器

在AngularJS中,表达式是一种类似于模板引擎的语,可以在书写的位置 “输出” 数据。

基本使用

  • 表达式写在双大括号内:\{\{ expression \}\}
  • 表达式 很像 JavaScript 表达式
  • 它们可以包含文字、运算符和变量
  • \{\{ 5 + 5 \}\}\{\{ firstName + lastName \}\}

支持的类型及操作符

  • 数字
  • 字符串
  • 对象
  • 数组
  • + - * /
  • 三目表达式
  • 短路运算符

如果是 null 或 undefined ,表达式不会报错。

Angular 表达式与 JavaScript 区别:

相同点:

都可以包含字母、操作符、变量

不同点:

  • AngularJS 表达式可以写在 HTML 中
  • AngularJS 表达式不支持条件判断,循环及异常
  • AngularJS 表达式支持过滤器

解决表达式闪烁的问题

ng 默认是在 document onload 的时候开始解析执行,ng 在启动执行的时候会自动向 head 中插入一个 style 样式。

  • ng-cloak
  • ng-bind

详细说明:

解决表达式闪烁方式有两种:

第一种方式:

将 ng 脚本引入到 head 中,ng 官方推荐将 ng 脚本引入最上面;
在所有使用了表达式的外部的节点上加一个属性 ng-cloak;
当加上 ng-cloak 属性的时候,ng 不会等待 DOM onload 执行结束就会先在加了 ng-cloak 的地方作用一个样式 display: none !important;
当 ng 解析完毕之后,ng-cloak(样式) 被自动移除。

第二种方式:

在所有使用表达式的地方都通过 ng-bind 指令来代替;
也就是说使用了 ng-bind 可以完全替代表达式;
用了它就可以解决将 ng脚本引入底部也不闪烁的问题。

AngularJS 指令

AngularJS 指令是以 ng- 作为前缀的 HTML 属性,AngularJS 通过内置的指令来为应用添加功能,AngularJS 同时允许自定义指令,从而构建更加超动感的 HTML。

HTML5 允许扩展的(自制的)属性,以 data- 开头。AngularJS 属性以 ng- 开头,但是也可以使用 data-ng- 来让网页对 HTML5 有效。

指令的使用形式

  • ng-xxx 的属性本身并不是标准中定义的属性
  • 很多情况下无法通过语法校验
  • HTML5 允许扩展的属性,以 data- 开头
  • 在 ng 中可以使用 data-ng- 作为前缀来让网页对 HTML5 有效
  • 二者效果相同

内置指令

AngularJS 内置了很多指令,用来增强 HTML,以下是一些常用内置指令的介绍。

ngApp

  • ng-app

ngController

ngInit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>ng - 双向绑定</title>
</head>
<body ng-app ng-init="name='World'">
<!-- input 的 value 和模型中的 name 建立双向绑定关系 -->
<input type="text" ng-model="name">
<!--
input 的 value 和模型中的 age 建立双向绑定关系
age 不一定初始化,可以直接使用,当你直接使用的时候,会自动去模型中初始化 age,只不过没有值而已
如果想要给 age 初始化数据,就可以通过 ng-init 的方式,给 age 初始化一个值
ng-init 以后也会很少适应,这里是为了案例演示
-->
<input type="text" ng-model="age">
<h1>Hello {{name}}</h1>
<h1>年龄 {{age}}</h1>
<script src="js/angular.js"></script>
</body>
</html>

ngBind

  • ng-bind
  • ng-non-bindable

ngBindHtml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<body ng-app="DemoApp" ng-controller="DemoController">
<div>
<h1 ng-bind="title"></h1>
<div ng-bind-html="content"></div>
</div>
<script src="js/angular.js"></script>
<script src="../node_modules/angular-sanitize/angular-sanitize.js"></script>
<script>
// 如果想要绑定 HTML 字符串,则必须使用这种方式
// 1. npm install --save angular-sanitize
// 2. 在使用该字符串的所属的模块中加载 ngSanitize 模块即可生效
angular.module('DemoApp', ['ngSanitize']).controller('DemoController', ['$scope', function ($scope) {
$scope.title = '使用ngSanitize 模块绑定 HTML 字符串'
$scope.content = '<script>window.alert("hello")<\/script><p>作者:xxx</p> <p><strong>Hiraku</strong>如何绑定</p>'
}]);
</script>
</body>

ngRepeat

  • ng-repeat
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<body ng-app="DemoApp" ng-controller="DemoController">
<table>
<thead>
<tr><th>编号</th><th>姓名</th><th>年龄</th><th>性别</th></tr>
</thead>
<tbody>
<tr ng-repeat="friend in friends"><td>{{$index+1}}</td><td>{{friend.name}}</td><td>{{friend.age}}</td><td>{{friend.gender}}</td></tr>
</tbody>
</table>
<ul>
<!-- 利用 track by $index 解决重复项报错问题 -->
<li ng-repeat="fruit in fruits track by $index">{{fruit}}</li>
</ul>
<script src="../code/js/angular.js"></script>
<script>
angular.module('DemoApp', []).controller('DemoController', ['$scope', function ($scope) {
/* beautify ignore:start */
$scope.friends = [{name:'John', age:25, gender:'boy'},{name:'John', age:25, gender:'boy'}, {name:'Jessie', age:30, gender:'girl'}];
// ng-repeat 在遍历普通数据类型的时候,如果有相同的值,会报错;在使用 ng-repeat 的时候,都最好加上 track by $index 来避免这个问题
$scope.fruits = ['🍎','🍎', '🍌', '🍐', '🍉'];
/* beautify ignore:end */
}]);
</script>
</body>

解决重复项报错问题

ngClass

  • ng-class
  • ng-class-even
  • ng-class-odd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<body ng-app="DemoApp" ng-controller="DemoController">
点击切换字体颜色:<input type="checkbox" ng-model="isRed">
点击切换背景色:<input type="checkbox" ng-model="isGreen">
<p ng-class="{red: isRed, green: isGreen}">ng-class 的使用</p>
<ul><li ng-repeat="friend in friends" ng-class-odd="'bgRed'" ng-class-even="{bgGreen: isGreen}">
{{friend.name}} - {{friend.age}} - {{friend.gender}}
</li></ul>
<script src="../code/js/angular.js"></script>
<script>
angular.module('DemoApp', []).controller('DemoController', ['$scope', function ($scope) {
$scope.friends = [{name:'John', age:25, gender:'boy'}, {name:'John', age:25, gender:'boy'}, {name:'Jessie', age:30, gender:'girl'}];
}]);
</script>
</body>

ng-cloak

ng-hide-show-if-switch

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
<body ng-app="DemoApp" ng-controller="DemoController">
<input type="checkbox" ng-model="loading">
<img ng-show="loading" src="img/loading-green-3.gif" alt="">
<img ng-hide="!loading" src="img/loading-green-3.gif" alt="">
<select ng-model="selection">
<option ng-repeat="city in cities" value="{{city.id}}">{{city.name}}</option>
</select>
<div ng-switch on="selection">
<div ng-switch-when="1">北京</div>
<div ng-switch-when="2">上海</div>
<div ng-switch-when="3">广州</div>
</div>
<img ng-if="loading" src="./img/loading-green-3.gif" alt="">
<script src="../code/js/angular.js"></script>
<script>
angular.module('DemoApp', []).controller('DemoController', ['$scope', '$timeout', function ($scope, $timeout) {
$scope.loading = true;
setTimeout(function () {
// 如果在普通的定时器函数内部修改了 $scope 视图模型成员,一定要通过 $scope.$apply() 手动刷新视图模型才行
$scope.loading = false;
$scope.$apply();
}, 10000)
// $timeout(function () {
// $scope.loading = false;
// }, 2000);
$scope.cities = [{id: 1, name: '北京'}, {id: 2, name: '上海'}, {id: 3, name: '广州'}];
}]);
</script>
</body>

ng-if-hide-show 的区别

  • ng-if 是直接就不渲染这个 DOM 了
    • 当为 true 的时候直接渲染
    • 当为 false 的时候直接移除该元素
  • ng-hide/ng-show
    • 两者无论是 true 还是 false 元素都在,是通过样式来控制的

ng-src

所有需要动态指定 src 的地方都通过 ng-src 来替换,否则浏览器会真的对这个 src 发起请求

其它常用指令

  • ng-checked : 单选/复选是否选中,只是单向绑定数据
  • ng-disabled : 是否禁用
  • ng-readonly : 是否只读
  • ng-selected : 是否选中,只是单向数据绑定

事件型指令

  • ng-click :鼠标单击
  • ng-blur :失去焦点
  • ng-focus :得到焦点
  • ng-change :发生改变
  • ng-copy :拷贝完成
  • ng-dblclick :鼠标双击
  • ng-submit:表单提交
  • ng-copy
  • ng-cut
  • ng-paste
  • ng-keydown
  • ng-keyup
  • ng-mousedown
  • ng-mouseenter
  • ng-mouseleave
  • ng-mouseover
  • ng-mouseup
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<head>
<meta charset="UTF-8">
<title>ng - 购物车计价器</title>
</head>
<body ng-app ng-init="price=9.9; count=6;">
单价:
<input type="number" ng-model="price">
<br>
<br>
<button ng-click="count = count - 1 <= 0 ? 0 : count - 1">-</button>
<span>{{count}}</span>
<button ng-click="count = count + 1">+</button>
<br>
<p>{{price * count | number:2}}</p>
<p>{{'abc' | uppercase}}</p>
<p>{{'ABC' | lowercase}}</p>
<script src="js/angular.js"></script>
</body>
</html>

ng 中也提供了一些单向数据绑定的指令

也就是说只能通过模型获取到数据,但是不能通过改变元素值而影响视图模型数据。

视图数据模型:$scope

  • $scope 是用来视图和数据之间的胶水、粘合剂
  • 视图和控制器之间的数据桥梁
  • 用于在视图和控制器之间传递数据
  • 用来暴露数据模型(数据、行为)
  • 监视模型数据的变化,做出相应的动作 $scope.$watch

如何设计 $scope

根据原型抽象数据和行为:

  • 数据
  • 行为

ViewModel

ng 官方把自己定义为一个 MVC 框架。很多开发使用者把它称之为 MVVM 框架。

  • $scope 实际上就是 MVVM 中所谓的 VM(视图模型)
  • 正式因为 $scope 在 ng 中大量使用甚至盖过了 c 的概念,所以很多人把 ng 称之为 mvvm 框架

数据模型作用域

把所有的根据视图抽象出来的成员都放到一个控制器函数中也就是都放到到一个 $scoep 中,绝对没有问题,但是这么做,可维护性太差了,毫不相干的业务都放到一起了。所以就可以为不同的业务视图划分不同的作用域,根据不同的业务划分不同的控制器函数,得到对应的 $scope 作用域数据模型对象,不同的作用域作用于不同的视图访问不同的数据和行为,作用域可以嵌套,可以访问嵌套关系的作用域成员。

ng 1.5 以下版本使用视图数据模型定义过程:

  1. 引包
  2. 定义全局控制器函数
    • 主要目的就是为了把逻辑写到 JavaScript 代码中
    • 其次是为了拿到那个 $scope 数据模型对象
    • 然后通过操作 $scoep 数据模型,和视图作交互
  3. 根据视图暴露模型数据成员
    • 给 $scope 初始化一些数据成员
    • 同时暴露一些行为函数
  4. 设置入口标识 ng-app
    • 设置控制器
      • 目的就是为了让你的视图和 $scope 建立作用关系
      • 通过操作 $scope 和视图交互
      • 把以前对 DOM 的操作变成对 $scope 数据模型对象的操作

在 ng 1.5 之后,就不允许定义全局控制器函数了

控制器:Controller

  • ng 中的控制器用来对 scope 进行操作
    • 包括初始化数据和定义事件响应函数等
  • ng 用来解耦业务逻辑层和视图层的关键
  • controller 操作 scope,View 则展现 scope 的内容
  • 传统前端程序中大量复杂的 DOM 操作逻辑都被转变成对 scope 的操作

定义控制器的三种方式

定义控制器可以有三种方式,注意第一种已经被淘汰。

第一种:传统方式,使用全局函数定义控制器:

1
2
3
function DemoCtrl($scope) {
// code here
}

第二种:挂载在某个模块下

1
2
3
4
angular.module('DemoApp', [])
.controller('DemoCtrl', function ($scope) {
// code here
})

第三种:最正确的方式

1
2
3
4
5
// 解决因为代码压缩造成注入对象失败问题的方式就是将第二个参数换成一个数组
angular.module('DemoApp', [])
.controller('DemoCtrl', ['$scope', '$log', function ($scope, $log) {
// code here
}])

控制器定义例子:

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
50
51
52
53
54
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>ng - 控制器</title>
</head>
<body ng-app="DemoApp">
<div ng-controller="DemoController">
{{name}}
</div>
<div ng-controller="Demo1Controller">
{{name}}
</div>
<div ng-controller="Demo2Controller">
{{name}}
</div>
<script src="js/angular-1.2.3.js"></script>
<script>
// 在 ng 1.5 之后,就不允许定义全局控制器函数了
// 之前定义控制器的方式也有解决方案,就是模块化,已不再使用
function DemoController($scope) {
$scope.foo = 'bar';
}
// 创建控制器,有问题,启用标识符混淆压缩会把 $scope 压缩掉,代码就报错了
var demoApp = angular.module('DemoApp', []).controller('DemoController', function ($scope) {
$scope.name = 'DemoController';
});
// 通过模块变量定义控制器
demoApp.controller('Demo1Controller', function ($scope) {
$scope.name = 'Demo1Controller';
});
// 这里表示直接获取,前提是 DemoApp 已经定义过了
angular.module('DemoApp').controller('Demo2Controller', function ($scope) {
$scope.name = 'Demo2Controller';
});
// 以上三种形式都是基于模块定义控制器,链式编程、通过模块变量定义、通过获取模块定义 都一样,想用哪种用哪种
// 创建控制器最正确的方式,这种方式不会被混淆代码压缩影响
var demoApp = angular.module('DemoApp', []).controller('DemoController', ['$scope', function ($scope) {
$scope.name = 'DemoController';
}]);
demoApp.controller('Demo1Controller', ['$scope', function ($scope) {
$scope.name = 'Demo1Controller';
}]);
angular.module('DemoApp').controller('Demo2Controller', ['$scope', function ($scope) {
$scope.name = 'Demo2Controller';
}]);
</script>
</body>
</html>

如何划分控制器

一个页面中,按照不同的功能业务划分不同的控制器。

模块:Module

  • 模块定义了一个应用程序
  • 模块是应用程序中不同部分的容器
  • 模块是应用控制器的容器
  • 控制器通常属于一个模块

ng 中模块的引入最重要的目的就是为了解决原来全局定义的控制器污染的问题,还有一个目的就是让我们以模块的形式划分架构。

可以通过 angular.module() 方法操作模块
注意:该方法只有在传入两个参数时才会创建模块,否则为获取已有模块

定义模块

定义一个模块:

1
2
// 注意:必须指定第二个参数,否则变成获取已定义的模块
var demoApp = angular.module('DemoApp', [])

获取已有模块:

1
var demoApp = angular.module('DemoApp')

定义依赖别的模块的模块:

1
var demoApp = angular.module('DemoApp', ['Module1', 'Module2'])

定义模块和控制器(利用模块定义控制器)

  1. 定义一个模块 angular.module('模块名', [])
    • 如果是一个参数,就表示获取一个模块
    • 如果两个参数,第二个参数就必须是一个数组
      • 这个数组表示该模块的依赖,空数组表示没有任何依赖,同时创建该模块
      • 如果有依赖,在数组中指定依赖的模块名即可
  2. 在该模块下去定义控制器
  3. 将模块和控制器作用到视图

如何划分模块

加载多个模块

  • angular.bootstrap(document, ['demo'])
  • angular.module('MainModule', ['Module1', 'Module2', 'Module3'[,ModuleName]])

模块例子:

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
<head>
<meta charset="UTF-8">
<title>ng - 模块</title>
</head>
<body ng-app="MainModule">
<div ng-controller="Demo1Controller">
{{name}}
</div>
<div ng-controller="Demo2Controller">
{{name}}
</div>
<div ng-controller="MainController">
{{name}}
</div>
<script src="js/angular.js"></script>
<script>
// 创建了一个模块(没有任何依赖项)
// Angular 中的模块不像一些 CMD、CommonJS、AMD 等模块定义规范
// 有输入有输出
// Angular 中的模块中的输入与输出(加载模块依赖、暴露模块成员)体现不够明显
// Angular 中的模块也不能通过代码去主动的加载另一个模块
// Angular 中的模块唯一体现的地方在于:
// 1. 解决原来全局控制器命名污染的问题
// 2. 解决按照不同的页面,将不同的控制器组织到一起
angular.module('Demo1App', []).controller('Demo1Controller', ['$scope', function ($scope) {
$scope.name = 'Demo1Controller';
}]).controller('MainController', ['$scope', function($scope){
$scope.name = 'Demo1App MainController';
}]);
angular.module('Demo2App', []).controller('Demo2Controller', ['$scope', function ($scope) {
$scope.name = 'Demo2Controller';
}]);
// 手动引导模块的启动,可以启动多个模块,但是都必须作用到一个元素上;这种方式不推荐使用
angular.bootstrap(document.getElementById('body'), ['Demo1App', 'Demo2App']);
// 定义一个主模块,加载依赖的模块
angular.module('MainModule', ['Demo1App', 'Demo2App']).controller('MainController', ['$scope', function ($scope) {
$scope.name = 'MainModule MainController';
}]);
</script>
</body>
</html>

过滤器:Filter

内置过滤器

  • currency
  • number
  • date
  • json
  • uppercase
  • lowercase
  • orderBy
  • limitTo
  • filter

自定义过滤器

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
<body ng-app="DemoApp" ng-controller="DemoController">
<p>{{time | date:'yyyy-MM-dd HH:mm:ss'}}</p>
<p>{{time | date:'yyyy-MM-dd HH:mm:ss Z'}}</p>
<p>{{time | date:'yyyy-MM-dd HH:mma'}}</p>
<p>{{time | date:'medium'}}</p>
<p>{{ user | json }}</p>
<pre>{{ user | json:4 }}</pre><hr>
<label for="">搜索:</label><input type="text" ng-model="searchText">
<table>
<thead><tr><th>姓名</th><th>电话</th></tr></thead>
<tbody><tr ng-repeat="friend in friends | filter:searchText track by $index"><td>{{friend.name}}</td><td>{{friend.phone}}</td></tr></tbody>
</table><hr><hr>
<label>匹配任意项: <input ng-model="search.$"></label> <br> {$: 'xxx'}
<label>根据名字筛选: <input ng-model="search.name"></label><br> {name: 'xxx'}
<label>Phone only <input ng-model="search.phone"></label><br> {phone: 'xxx'}
<label>Equality <input type="checkbox" ng-model="strict"></label>
<table>
<thead><tr><th>姓名</th><th>电话</th></tr></thead>
<tbody><tr ng-repeat="friend in friends | filter:search:strict track by $index"><td>{{friend.name}}</td>td>{{friend.phone}}</td></tr></tbody>
</table>
<script src="../code/js/angular.js"></script>
<script>
angular.module('DemoApp', []);.controller('DemoController', ['$scope','$filter', function ($scope, $filter) {
$scope.time = new Date();
$scope.user = {name: 'Jack',age: 18};
console.log($filter('date')($scope.time, 'yyyy-MM-dd HH:mm:ss'));
$scope.friends = [{name:'John', phone:'555-1276'},{name:'Mary', phone:'800-BIG-MARY'},{name:'Mike', phone:'555-4321'}];
$scope.searchText = '';
$scope.search = {};
}]);
</script>
</body>

服务:Service

在 Angular 中,服务的概念和后台的服务概念基本是一样的,差别只是在于技术细节。

服务是对公共代码的抽象,比如,如果在多个控制器中都出现了相似的代码,那么把它们提取出来,封装成一个服务,在可维护性方面获得提升。

然而,在工程实践中,引入服务的主要目的是为了优化代码结构,而不是复用。复用只是一项结果,而不是目标。

Angular 调试

将 $scope 模型对象挂载给 window

不推荐使用,麻烦

Chrome 插件:AngularJS Batarang

  • 安装插件

基本使用:

  1. 以 http 协议访问你要调试的页面
  2. 打开控制台,找到 AngularJS
  3. 选择 Enable 启用调试
  4. 切换到 Scope 选项卡

MVVM

M: Model

M: 数据模型

V

V: 视图

VM

ViewModel: 视图模型

C

用来处理视图模型和视图的交互的

使用 ng 总结

  • AngularJS 最大程度上减少了页面上的 DOM 操作
  • 让开发人员更专注于业务操作
  • 通过简洁的指令结合页面结构与逻辑数据
  • 通过自定义指令实现组件化编程
  • 代码结构更合理
  • 维护成本更低
  • AngularJS 解放了传统 JavaScript 中频繁的 DOM 操作
感谢您的支持!