简单入门

下载与使用

下载地址:https://angularjs.org,点 DEVELOP / Download,找到 angularjs-1.x.x.zip 为全部文件

引入文件

1
<script src="js/angular.js"></script>

数据绑定

ng-app

1
2
3
4
5
6
7
8
9
10
11
12
<html>
<head>
<meta charset="UTF-8">
<title></title>
<script src="js/angular.js"></script>
</head>
<body>
<div ng-app> <!-- ng-app 表示作用域 -->
<h1>{{1+2}}</h1>
</div>
</body>
</html>

ng-app表示Angular的作用于,在一个HTML文档中有且只能有一个。如果有多个,以第一个为准。所以ng-app一般放在<html>标签中。

可以使用 <html ng-app>,也可以是 <html ng-app="">

Angular中数据使用双花括号{\{}\}表示数据

ng-init

声明变量并赋初值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<html ng-app>
<head>
<meta charset="UTF-8">
<title></title>
<script src="js/angular.js"></script>
</head>
<body>
<!-- 后面部分代码,html/head/body略,仅记录重要部分 -->
<h1>{{1+2}}</h1> <!-- 常量 -->
<h1 ng-init="a=1; b='字符串'; c={'name':'张三', 'age':18}"></h1>
<h2>{{a}}</h2> <!-- 变量 -->
<h2>{{"a"}}</h2> <!-- 字符串常量 -->
<h2>姓名:{{c.name}}</h2>
<h2>年龄:{{c.age}}</h2>
</body>
</html>

ng-model

数据与HTML元素绑定,修改元素内容则修改对应数据,以及所有显示该数据的元素

<element ng-model="name"></element>

<input>/<select>/<textarea>元素支持该指令

1
2
3
4
5
<h1 ng-init="p={'name':'张三', 'age':18}"></h1>
<h2>姓名:{{p.name}}</h2>
<h2>年龄:{{p.age}}</h2>
<input type="text" ng-model="p.name"/>
<input type="number" ng-model="p.age"/>

模块和控制器

模块的创建

语法:angular.module("app", []); 其中”app”是HTML中唯一一个ng-app="app"的值

依赖:require(字符串数组)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<html ng-app="app">

<head>
<meta charset="UTF-8">
<title></title>
<script src="js/angular.js"></script>
</head>

<body>
<!-- Code... -->
</body>

<script>
angular.module('app', []); // 创建模块
</script>

</html>

控制器

$scope绑定的是数据模型,可直接使用 $scope.xxx

1
2
3
4
5
6
7
8
9
10
11
<body ng-controller="ctrl"> <!-- 表示对应的控制器是 ctrl -->
<h1>{{name}}</h1> <!-- 相当于 $scope.name,即 张三 -->
</body>

<script>
var myApp = angular.module('app', []);

myApp.controller("ctrl", ["$scope", function($scope) {
$scope.name = '张三';
}]);
</script>

常用指令

ng-repeat

循环输出指定次数的HTML元素,集合必须是数组或对象

  • 方式1:item in list
  • 方式2:(key, value) in list
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
<body ng-controller="ctrl">
<!-- 循环数组 -->
<ul>
<li ng-repeat="s in scores">
<h2>{{s.name}}-{{s.score}}</h2>
</li>
</ul>
<hr>
<!-- 循环对象 -->
<ul>
<li ng-repeat="(key, value) in person">
<h2>{{key}}-{{value}}</h2>
</li>
</ul>
<hr>
<!-- 双重循环,使用对象的方式循环数组 -->
<ul>
<li ng-repeat="s in scores">
<h2 ng-repeat="(key, value) in s">
{{key}}-{{value}}
</h2>
</li>
</ul>
</body>

<script>
var myApp = angular.module('app', []);

myApp.controller('ctrl', ["$scope", function ($scope) {
// 数组
$scope.scores = [
{ "name": "语文", "score": 88 },
{ "name": "数学", "score": 100 },
{ "name": "英语", "score": 98 }
];

// 对象
$scope.person = {"name": "张三", "age": 18};
}]);
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
·语文-88
·数学-100
·英语-98
---------
·name-张三
·age-18
---------
·name-语文
score-88
·name-数学
score-100
·name-英语
score-98

循环索引

所有下标都是从 0 开始

  • $index 循环的索引
  • $first 是否是第一项
  • $last 是否是最后一项
  • $middle 是否是中间项(非第一、最后第一)
  • $odd 下标是否是奇数(第0项false
  • $even 下标是否是偶数(第0项true
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
<body ng-controller="ctrl">
<div class="container">
<table class='table table-bordered'>
<tr ng-repeat="item in list">
<td>{{$index}}</td>
<td>{{item.name}}</td>
<td>{{item.age}}</td>
<td>{{$first}}</td>
<td>{{$odd}}</td>
</tr>
</table>
</div>
</body>

<script>
var myApp = angular.module('app', []);

myApp.controller('ctrl', ["$scope", function ($scope) {
$scope.list = [
{'name': '张三1', 'age': 18},
{'name': '张三2', 'age': 18},
{'name': '张三3', 'age': 18},
{'name': '张三4', 'age': 18},
{'name': '张三5', 'age': 18},
];
}]);
</script>

ng-class

给HTML元素动态绑定一个或多个CSS类

  • 如果值是字符串,多个类名用空格分隔
  • 如果值是对象,需要使用 key-value 的方式,key 为要添加的类名,value 是布尔值,仅在为 true 时添加
  • 如果值是数组,可以由字符串或对象组合组成,数组的元素可以是字符串或对象
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
<html ng-app="app">

<head>
<meta charset="UTF-8">
<title></title>
<link rel="stylesheet" href="css/bootstrap.min.css" />
<script src="js/angular.js"></script>
</head>

<body ng-controller="ctrl">
<div class="container">
<!-- 字符串的方式:(字符串常量在双引号里面再加一个单引号) -->
<div ng-class=" 'btn-primary text-center' ">方式1</div>
<!-- 对象的方式:name-bool -->
<div ng-class="{ 'bg-info': true }">方式2.1</div>
<div ng-class="{ 'bg-info': isAdd }">方式2.2</div> <!-- 使用控制器中的变量 -->
<!-- 数组的方式 -->
<div ng-class="[ 'btn-primary', 'text-right' ]">方式3</div>
</div>
</body>

<script>
var myApp = angular.module('app', []);

myApp.controller('ctrl', ["$scope", function ($scope) {
$scope.isAdded = false; // 是否添加一个类
}]);
</script>

</html>

ng-click

元素被点击后需要执行的操作,所有 HTML 元素都支持

<element ng-click="express"></element>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<body ng-controller="ctrl">
<div class="container">
<div class="btn btn-primary" ng-click="temp=!temp">
点击后切换下面H1的class的开关
</div>
<h1 ng-class="{ 'bg-primary': temp, 'bg-danger': !temp }">
使用对象的方式开关类
</h1>
</div>
</body>

<script>
var myApp = angular.module('app', []);

myApp.controller('ctrl', ["$scope", function ($scope) {
$scope.temp = true; // 赋初值
}]);
</script>

function

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-controller="ctrl">
<div class="container">
<h1 ng-class="{ 'btn-primary': temp }">{{name}}</h1>
<!-- 普通的单击方式 -->
<div class="btn btn-success" ng-click="name='李四'">修改姓名</div>
<!-- 使用function的单击方式 -->
<div class="btn btn-success" ng-click="change()">修改姓名2</div>
</div>
</body>

<script>
var myApp = angular.module('app', []);

myApp.controller('ctrl', ["$scope", function ($scope) {
$scope.name = "张三";

$scope.temp = false;
$scope.change=function() {
$scope.name = "王五";
$scope.temp = true;
};
}]);
</script>

元素的显示与隐藏

ng-show、ng-hide

元素的显示或隐藏时通过改变CSS的display属性值来实现的

1
<h1 ng-show="false"></h1>

ng-show=falseng-hide=true 时,会自动给元素添加上:class="ng-hide"

ng-if

在表达式为 false 时移除 HTML 元素;true 时会添加移除的元素并显示

ng-if 不同于 ng-hide。ng-hide 是隐藏元素,而 ng-if 是从 DOM 中移除元素

1
2
3
4
<body ng-controller="ctrl" ng-init="check=true">
<h1 ng-if="check==true">文字文字</h1>
<button ng-click="check = !check">按钮</button>
</body>

ng-switch

根据表达式显示或隐藏对应的部分。

  • ng-switch-when: 如果匹配选中选择显示
  • ng-switch-default: 如果都没有匹配,则默认显示
1
2
3
4
5
6
7
8
<body ng-controller="ctrl" ng-init="val='b'">
<div ng-switch="val">
<h1 ng-switch-when="a">选项一</h1>
<h1 ng-switch-when="b">选项二</h1>
<h1 ng-switch-when="c">选项三</h1>
<h1 ng-switch-default>默认</h1>
</div>
</body>

不同控制器的数据共享

父子关系

  • controller / $scope 可以继承父 controller$scope 对象
  • controller$scope 同名字段会替换掉父容器的同名字段
  • 父级 controller 里定义一个方法,操作父级的 scope 对象,在子级 controller 里调用该方法,实现了子父通讯
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<body ng-controller="ctrl">
<h1>父级的标题-{{myTitle}}</h1> <!--父级的标题-->
<div ng-controller='innerCtrl'>
<h1>子级的标题-{{myTitle}}</h1> <!--父级的标题-->
</div>
</body>

<script>
var myApp = angular.module('app', []);

myApp.controller('ctrl', ["$scope", function ($scope) {
$scope.myTitle = '父级的标题';
}]);

myApp.controller('innerCtrl', ["$scope", function ($scope) {

}]);
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<body ng-controller="ctrl">
<h1>父级的标题-{{myTitle}}</h1> <!--父级的标题-->
<div ng-controller='innerCtrl'>
<h1>子级的标题-{{myTitle}}</h1> <!--子级的标题-->
</div>
</body>

<script>
var myApp = angular.module('app', []);

myApp.controller('ctrl', ["$scope", function ($scope) {
$scope.myTitle = '父级的标题';
}]);

myApp.controller('innerCtrl', ["$scope", function ($scope) {
$scope.myTitle = '子级的标题'; // 覆盖了父级
}]);
</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
<body ng-controller="ctrl">
<h1>父级的标题-{{myTitle}}</h1>
<span class="btn btn-primary" ng-click="changeTitle()">点击切换标题</span>
<div ng-controller='innerCtrl'> <!-- 子控制器 -->
<h1>子级的标题-{{myTitle}}</h1>
<span class="btn btn-primary" ng-click="changeTitle()">点击切换标题</span>
</div>
</body>

<script>
var myApp = angular.module('app', []);

myApp.controller('ctrl', ["$scope", function ($scope) {
$scope.myTitle = '父级的标题';

$scope.changeTitle = function() {
$scope.myTitle = '父级的标题2'; // 只改变父级
}
}]);

myApp.controller('innerCtrl', ["$scope", function ($scope) {
$scope.myTitle = '子级的标题';

$scope.changeTitle = function () {
$scope.myTitle = '子级的标题2'; // 只改变子级
}
}]);
</script>

$rootScope

scope是html和单个controller之间的桥梁,数据绑定就靠他了。rootscope是各个controller中的桥梁。用rootscope定义的值,可以在各个controller中使用

$rootScope是由angularjs加载模块的时候自动创建的,每个模块只会有1个rootScope

简而言之:$rootScope就是全局对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<body>
<div ng-controller="ctrl">
<h1>{{title}}</h1> <!-- 控制器一 -->
<h1>{{content}}</h1> <!-- 全局rootScope内容 -->
</div>
<div ng-controller="ctrl2">
<h1>{{title}}</h1> <!-- 不显示内容 -->
<h1>{{content}}</h1> <!-- 全局rootScope内容 -->
</div>
</body>

<script>
var myApp = angular.module('app', []);

myApp.controller('ctrl', ["$scope", "$rootScope", function ($scope, $rootScope) {
$scope.title='控制器一';
$rootScope.content='全局rootScope内容';
}]);

myApp.controller('ctrl2', ["$scope", function ($scope) {

}]);
</script>

监听变化

$watch

用于监听模型的变化

$watch(watchExpression, listener, objectEquality);

  • 参数一:监听的对象,可以是表达式如'name',或函数function() { return $scope.name }
  • 参数二:变化时要调用的函数或表达式,接收三个参数:
    • 参数一:newValue 新值
    • 参数二:oldValue 旧值(watchExpression 表达式的值)
    • 参数三:scope 作用域
  • 参数三:是否深度监听。若true,则检查所监控的对象中每一个属性的变化。
    如果要监控数组的个别元素或者对象的属性而不是一个普通的值,那么应该使用他
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<script>
var myApp = angular.module('app', []);

myApp.controller('ctrl', ["$scope", function ($scope) {
$scope.title = 'a';
$scope.title2 = 'b';
$scope.$watch('title==title2', function(newVal, oldVal, scope){
/* 检测到 title==title2 表达式值发生变化时 */
});

$scope.user = {
"name": "张三",
"age": 20
};
$scope.$watch('user', function(newVal, oldVal, scope){
/* 检测到 user 值发生变化时 */
console.log(JSON.stringify(newVal));
});
}]);
</script>

$apply

传播 module 变化

1
2
3
4
5
6
7
8
// 错误用法
myApp.controller('ctrl', ["$scope", function ($scope) {
$scope.num = 0;
setInterval(function () { // 原生JS定时器
// 这个语句不会及时更改界面,因为更改num时,Angular不知道值改变了
$scope.num++;
}, 1000);
}]);
1
2
3
4
5
6
7
8
myApp.controller('ctrl', ["$scope", function ($scope) {
$scope.num = 0;
setInterval(function () {
$scope.$apply(function () { // 放在 $apply 里面,则可以立马监听到值改变了
$scope.num++;
});
}, 1000);
}]);
1
2
3
4
5
6
7
8
9
// 使用Angular自带定时器,免apply
myApp.controller('ctrl', ["$scope", "$interval", function($scope, $interval) {
$scope.num = 0;
var timer = $interval(function() { // 自带的定时器
$scope.num++;
if ($scope.num == 10)
$interval.cancel(timer); // 取消定时器
}, 1000);
}]);

$ng-bind

使用给定的变量或表达式的值来替换 HTML 元素的内容

如果给定的变量或表达式修改了,指定替换的 HTML 元素也会修改

nb-bind作用和{\{}\}是一样的

用双大括号的形式,浏览器会先加载HTML,再加载Angular。在网速慢或反应慢的时候,会先短暂出现一大堆的{\{}\},再消失

1
2
<h1>{{title}}</h1>
<h1 ng-bind="title"></h1>

框架搭建

表单验证

  • ng-minlength 最小长度
  • ng-maxlength 最大长度
  • ng-required 是否是必填项
  • ng-pattern 正则匹配
  • ng-disabled 指令设置表单输入字段的disabled属性(input, select, textarea),true时禁用
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
<form name="form1">
<div class="form-group">
<label class="col-sm-2 control-label">用户名</label>
<div class="col-sm-5">
<!-- 设置输入控件条件、必填项 -->
<input type="text" name="User" ng-model="UserName" class="form-control" ng-minlength="4" ng-maxlength="20" ng-required="true" />
</div>
<div class="col-sm-5">
<p class="form-control-static" ng-show="form1.User.$invalid">请输入4-20位用户名</p>
<!-- <p class="form-control-static" ng-hide="form1.User.$valid">请输入4-20位用户名</p> -->
</div>
</div>

<div class="form-group">
<label class="col-sm-2 control-label">手机号</label>
<div class="col-sm-5">
<!-- 使用正则表达式 -->
<input type="tel" name="tel" ng-model="tel" class="form-control" ng-model="tel" ng-pattern="/1[3578]\d{9}/" ng-required="true" />
</div>
<div class="col-sm-5">
<!-- 使用 $error 逐个验证 invalid 原因 -->
<p class="form-control-static" ng-show="form1.tel.$error.required">手机号不能为空</p>
<p class="form-control-static" ng-show="form1.tel.$error.pattern">请输入正确的手机号</p>
</div>
</div>

<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<!-- 所有输入控件有效时才允许输入 -->
<button type="submit" class="btn btn-primary" ng-disabled="form1.$invalid">注册</button>
</div>
</div>
</form>

ng-option

在表达式中使用数组来字段生成一个select中的option列表

用法:

是一个数组时:

1
$scope.names = ["Email", "Tobias", "Linus"];
  1. item for item in names

是一个对象数组

1
2
3
4
$scope.colors = [
{id:1, name:'black', shade:'dark'},
{id:2, name:'white', shade:'light'}
];
  1. c.name for c in colors 使用name作为列表
  2. c.id as c.name for c in colors 显示name,但是value是id;不加as则默认值为对象JSON
  3. c.id as c.name group by c.shade for c in colors 通过某一数组分组(二层树状)
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
<body ng-controller="ctrl">
<!-- ng-options设置下拉列表,ng-model(必须加上)设置默认值 -->
<select class="form-control" ng-options="a for a in names" ng-model="name"></select>

<!-- 第二种方式提前设置默认值(必须加上ng-model)。(别设置$scope.name默认值) -->
<select class="form-control" ng-options="a for a in names" ng-model="name">
<option value="">--请选择--</option>
</select>

<hr>
<!-- 遍历对象,并设置id<==name -->
<select class="form-control" ng-options="color.id as color.name for color in colors" ng-model="color"> </select>
<h1>选中了{{color}}</h1>
</body>

<script>
var myApp = angular.module('app', []);

// 使用Angular自带定时器,免apply
myApp.controller('ctrl', ["$scope", function ($scope) {
$scope.names = ["张三", "李四", "王五"];
$scope.name = "张三"; // 第二种方式不可设置此行name默认值,否则option默认值不生效

$scope.colors = [
{ id: 1, name: 'black', shade: 'dark' },
{ id: 2, name: 'white', shade: 'light' }
];
$scope.color='';
}]);
</script>

过滤器

filter,用来过滤变量的值,或者格式化输出,得到自己所期望的结果或格式

filter格式

  • data|filter 数据源|过滤器名称
  • data|filter:params 数据源|过滤器名称:过滤器参数
  • data|filter:param1:param2 添加多个参数
  • data|filter1:param|filter2:param 添加多个过滤器

常用过滤器

  • currency 数值格式化为货币格式,并自动每3位加逗号。{\{123 | currency}\}
  • data 日期格式化成需要的格式
  • number:num 用来精确浮点数,默认保留3位
  • limitTo:num 数据的截取
  • Lowercase\uppercase 大小写过滤器
1
2
3
4
5
6
7
8
9
<h1>货币符号过滤器:{{100|currency}}</h1> <!-- $100.00 -->
<h1>货币符号过滤器:{{100|currency:"¥"}}</h1> <!-- ¥100.00 -->
<h1>日期过滤器:{{now}}</h1> <!-- 2020-02-26T06:45:17.463Z -->
<h1>日期过滤器:{{now|date:"yyyy-MM-dd HH:mm:ss"}}</h1> <!-- 2020-2-26 06:45:17 -->
<h1>number过滤器:{{100.123456|number:2}}</h1> <!-- 100.12,默认保留3位 -->
<h1>limitTo过滤器:{{"文本左边截取"|limitTo:3}}</h1> <!-- 文本左 -->
<h1>小写过滤器:{{"aaaBBB"|lowercase}}</h1> <!-- aaabbb -->
<h1>大小过滤器:{{"aaaBBB"|uppercase}}</h1> <!-- AAABBB -->
<h1>多个一起用:{{"aaaBBB"|uppercase|limitTo:4}}</h1> <!-- AAAB -->
1
2
3
4
var myApp = angular.module('app', []);
myApp.controller('ctrl', ["$scope", function ($scope) {
$scope.now = new Date();
}]);

orderBy

格式:data|orderby:param

参数:

  1. 排序字段
  2. 是否逆向排序,true为逆向,默认false
  3. “-字段”该字段逆向

排序规则:

  • 数字:从小到大
  • 字符串:按照字母表排,数字优先级大于字母
  • 汉字:按照字库排序,不是按照拼音
1
2
3
4
5
<tr ng-repeat="i in list|orderBy:'name'"> <!-- 注意单引号 -->
<td>{{i.id}}</td>
<td>{{i.name}}</td>
<td>{{i.type}}</td>
</tr>
1
2
<tr ng-repeat="i in list|orderBy:'type':true"> <!-- 倒序 -->
<tr ng-repeat="i in list|orderBy:'-type'"> <!-- 同倒序 -->
1
<tr ng-repeat="i in list|orderBy:['type','-id']"> <!-- 多项:按type顺序、id倒序 -->

点击标题修改排序方式、顺序逆序:

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
<body ng-controller="ctrl">
<table class="table table-bordered">
<thead>
<tr>
<td ng-click="clickOrder('id')">ID</td>
<td ng-click="clickOrder('name')">name</td>
<td ng-click="clickOrder('type')">type</td>
</tr>
</thead>
<tbody>
<!-- 使用了两个变量:排序方式、是否逆序 -->
<tr ng-repeat="l in list|orderBy:orderType:reverse">
<td>{{l.id}}</td>
<td>{{l.name}}</td>
<td>{{l.type}}</td>
</tr>
</tbody>
</table>
</body>

<script>
var myApp = angular.module('app', []);

// 使用Angular自带定时器,免apply
myApp.controller('ctrl', ["$scope", function ($scope) {
$scope.orderType = 'id';
$scope.reverse = false;
$scope.list = [
{"id": 1, "name": "北京", "type": "a"},
{"id": 2, "name": "上海", "type": "b"},
{"id": 3, "name": "山东", "type": "a"},
{"id": 4, "name": "江苏", "type": "b"},
{"id": 5, "name": "浙江", "type": "b"},
];

$scope.clickOrder = function(o) {
if ($scope.orderType == o) { // 切换顺序/逆序
$scope.reverse = !$scope.reverse;
} else {
$scope.reverse = false;
$scope.orderType = o;
}
}
}]);
</script>

filter

格式:data|filter:param

  1. 第一个参数为字符串表示会搜索所有的字段
  2. 第一个参数为对象 {"key":""},key 为字段名称,只查找该字段
  3. {"$":""} 全属性查找
  4. 第二个参数为true时表示精确匹配;否则模糊匹配

列表关键词过滤示例

检测item的字段:根据 search 里面的内容,过滤下方 ul 的项目

1
2
3
4
5
6
<input type="text" class="form-control" ng-model="search" />
<ul class="list-group">
<li class="list-group-item" ng-repeat="l in list|filter:search">
<p>{{l.id}}-{{l.name}}-{{l.type}}</p>
</li>
</ul>

只过滤一个字段:

1
<li class="list-group-item" ng-repeat="l in list|filter:{'name':search}">

全属性中过滤(相等于不用字段):

1
<li class="list-group-item" ng-repeat="l in list|filter:{'$':search}">

精确匹配:某一字段完全等于search值

1
<li class="list-group-item" ng-repeat="l in list|filter:search:true">

省-市 过滤示例:

1
2
3
4
5
6
7
<select ng-model="province" ng-options="item.id as item.name for item in provinceList">
<option value="">--请选择省份--</option>
</select>
<!-- 市.provinceId = 省.id -->
<select ng-model="city" ng-options="item.id as item.name for item in cityList|filter:{'provinceId':province}">
<option value="">--请选择县市--</option>
</select>

自定义过滤器

1
2
3
4
5
App.filter("filterName", [function(){
return function(data) {
return data;
}
}])

示例:

1
2
3
4
5
6
7
8
9
10
11
12
// 不带参数的:四舍五入
myApp.filter("round", [function () {
return function (data) {
return Math.round(data);
}
}]);
// 带一个参数:乘以倍数
myApp.filter("multi", [function () {
return function (data, arg1) {
return data * arg1;
}
}]);

路由

使用路由需要引入第三方的js: angular-route.js

1
<script src="js/angular-route.js"></script>

配置路由

模块的config函数里面,需要依赖注入$routeProvider

1
2
3
4
5
6
7
8
var myApp = angular.module('app', ["ngRoute"]);
myApp.config(["$routeProvider", function ($routeProvider) {
$routeProvider.when("路由地址", {
template: "",
templateUrl: "",
controller: "",
});
}])

template

简单路由示例:

使用 ng-view 自动适应对应的 templatetemplateUrl,并套上对应的 controller

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

<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="css/bootstrap.min.css" />
<script src="js/angular.js"></script>
<script src="js/angular-route.js"></script>
</head>

<body ng-controller="ctrl">
<nav class="navbar navbar-inverse">
<ul class="nav navbar-nav">
<!-- AngularJS版本1.6之后,#后需要加一个感叹号 -->
<li><a href="#!">首页</a></li>
<li><a href="#!/list">列表</a></li>
<li><a href="#!/func">功能</a></li>
</ul>
</nav>
<div class="container">
<div ng-view>
<!-- 自动使用对应nav中template中的内容,不需要再写 -->
</div>
</div>
</body>

<script>
var myApp = angular.module('app', ["ngRoute"]);
myApp.config(["$routeProvider", function ($routeProvider) {
$routeProvider.when("/", {
template: "<h1>首页的内容</h1>",
}).when("/list", {
"template": "<h1>列表的内容</h1>",
}).when("/func", {
"template": "<h1>功能的内容</h1>",
}).otherwise("/");
}]);

myApp.controller('ctrl', ["$scope", function ($scope) {

}]);
</script>

</html>

templateUrl

路由至单独页面、每个页面单独的控制器:

注意:templateUrl 方式需要用 localhost/file.html 访问,浏览器直接读取本地文件将无效

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var myApp = angular.module('app', ["ngRoute"]);
myApp.config(["$routeProvider", function ($routeProvider) {
$routeProvider.when("/", {
templateUrl: "view/home.html", // 导航至对应页面
controller: "homeCtrl", // 该页面单独的控制器
}).when("/list", {
"templateUrl": "view/list.html",
controller: "listCtrl",
}).when("/func", {
"templateUrl": "view/func.html",
controller: "funcCtrl",
}).otherwise("/");
}]);

/* 多个控制器的数据互不影响 */
myApp.controller("homeCtrl", ["$scope", function($scope) {
}]);

myApp.controller("listCtrl", ["$scope", function($scope) {
}]);

myApp.controller("funcCtrl", ["$scope", function($scope) {
}]);

路由传参

配置路由时路径 path/:param1/:param2

获取参数:在控制器里面依赖注入 $routeParams,使用 $routeParams.param1 来获取参数

1
2
3
4
<!-- 子页面 -->
<a ng-init="name='test'">
<a href="#!/detail/:'hhh'">查看详情</a>
<a href="#!/detail/:name">查看详情</a>
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
<script>
var myApp = angular.module('app', ["ngRoute"]);
myApp.config(["$routeProvider", function ($routeProvider) {
$routeProvider.when("/", {
"templateUrl": "view/home.html",
"controller": "homeCtrl"
}).when("/list", {
"templateUrl": "view/list.html",
"controller": "listCtrl"
}).when("/func", {
"templateUrl": "view/func.html",
"controller": "funcCtrl"
}).when("/detail/:name", {
"templateUrl": "view/detail.html",
"controller": "detailCtrl"
}).otherwise("/list");
}]);

/* 多个控制器的数据互不影响 */
/* ... */

myApp.controller("detailCtrl", ["$scope", "$routeParams", function($scope, $routeParams) {
// 获取到的参数数据,在detail.html中使用并显示出来
$scope.name = $routeParams.name;
}]);
</script>

服务

所有服务都不能HTML中直接使用,必须要和控制器scope的某个值绑定

也可以把整个服务赋值给控制器成员变量,则相当于直接使用

factory

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
var myApp = angular.module('app', []);
// 服务注入到控制器(一般自己写的服务加在最后面)
myApp.controller('ctrl', ["$scope", "myService", function ($scope) {
$scope.msg = myService.msg;
$scope.num = myService.num;
$scope.sum = myService.sum(1,2);
}]);

// 服务里面可以嵌套另一个服务
myApp.factory("myService", ["number", function() {
return {
"msg": "hello", // 常量
"num": 10,
"sum": function(a, b) { // 功能性方法
return a + b * number.multi;
}
};
}]);

myApp.factory("number", [function(){
return {
multi:20
}
}]);

service

factory,只是把返回的数组改用this

1
2
3
4
5
myApp.service("myService", [function() {
this.sum = function(a, b) {
return a + b;
}
}]);

constant

一般常量用 constant 和 value

constant 一般用作不做修改的全局变量

1
2
3
4
5
6
7
8
myApp.controller("ctrl", ["$scope", "config", function($scope, config) {
$scope.config = config; // 赋值整个config,则可以直接如 {{config.bgColor}}
}]);

myApp.constant("myConfig", {
"version": "1.2.0",
"bgColor": "red"
});

value

1
2
3
myApp.value("data", {
"num": 10
});

provider

类似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
// 服务注入到 config。名称中**必须**再加上 `Provider` 后缀
// 只能用 $get 外面的
myApp.config(["calcProvider", function() {
console.log(calcProvider.msg);
}]);

// 在控制器中只能用 $get 里面的
myApp.controller("ctrl", ["$scope", "calc", function($scope, calc) {
$scope.num = calc.sum(1, 2);
}]);

myApp.service("calc", [function() {
// 只能在config函数里面使用
this.msg = "";
this.num = 10;

// $get 里面的对象只能在控制器controller中使用
this.$get = function() {
return {
sum: function(a, b) {
return a + b;
}
};
}
}]);

自定义指令

可以理解成在特定DOM元素上运行的函数,指令可以扩展成这个元素的功能

1
2
3
4
5
6
angular.module('myApp', [])
.directive('myDirective', [function() {
return {
restrict: "ESMA",
};
}]);

restrict、template、replace

  1. restrict 调用方式,值为:

    • E: 标签调用
    • A: 属性调用
    • C: 类名调用
    • M: 注释调用
  2. template 模板HTML

    模板必须有一个根元素,即最外层不能多个标签并行(包括 templateUrl 的文件)

  3. replace 指令标记是否被替换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<body>
<!--以下四种情况都会替换为 template 中内容-->
<hello-dir>E元素标签</hello-dir>
<div hello-dir>A属性方式</div>
<div class="hello-dir">C类名方式</div>
<!-- directive: hello-dir --> <!-- M注释方式,注意结尾要留空 -->
</body>

<script>
var myApp = angular.module('app', []);
// 驼峰命名法要改格式,调用改成:hello-dir
myApp.directive('helloDir', [function () {
return {
"restrict": "ESMA",
"template": "<h1>Hello, Directory</h1>",
"replace": true // 完全替换掉原来的标签;注释调用此项也必须要true
};
}]);
</script>

templateURL

  • 方式一:值为HTML路径

    1
    2
    3
    4
    5
    6
    7
    8
    // <hello>元素标签</hello>
    myApp.directive('hello', [function () {
    return {
    "restrict": "E",
    "templateUrl": "view/link.html", // 注意改文字必须有一个root标签
    "replace": true
    };
    }]);
  • 方式二:页面里添加一个script标签,type属性为:text/ng-templateid属性值自己定义,templateUrl的值就是这个script标签的id属性值(通过 id 进行关联)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    <body>
    <hello>元素标签的形式</hello>
    </body>

    <script>
    var myApp = angular.module('app', []);
    myApp.directive('hello', [function () {
    return {
    "restrict": "ECMA",
    "templateUrl": "tpl1"
    };
    }]);
    </script>

    <script type="text/ng-template" id="tpl1">
    <h1>第二种模板</h1>
    </script>

    transclude

    boolean,保留指令标记原有内容。默认 false(覆盖原内容)

    true 时原有内容被保留在模板页里有 ng-transclude 指令的元素中

    main.html

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    <body>
    <hello>
    <a>原有的内容</a>
    </hello>
    </body>

    <script>
    var myApp = angular.module('app', []);
    myApp.directive('hello', [function () {
    return {
    "restrict": "E",
    "templateUrl": "view/link.html",
    "transclude": true
    };
    }]);
    </script>

    link.html

    1
    2
    3
    4
    <div> <!-- 注意需要一个根标签 -->
    <div> 模板内容 </div>
    <div ng-transclude></div> <!-- 这里显示原来的内容 -->
    </div>

    scope

指令的scope有三种选择:

  • false (默认)

    可以直接使用父作用域中的变量,共享同一个model,修改数据会反映到父作用域
    即标签中使用ng-model

    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
    <!-- main.html -->
    <body ng-controller="ctrl">
    <h1>{{title}}</h1> <!-- 出现两个相同标题 -->
    <!-- 相当于两个input,修改任意一个model随之修改 -->
    <input type="text" ng-model="name" />
    <hello></hello> <!-- 这里替换为另一个相同model的input -->
    </body>
    <script>
    var myApp = angular.module('app', []);
    myApp.controller('ctrl', ["$scope", function ($scope) {
    $scope.name = "张三"; // 这是共享的变量
    }]);

    myApp.directive('hello', [function () {
    return {
    "restrict": "E",
    "templateUrl": "view/link.html",
    "controller": ["$scope", function($scope) { // 声明一个子控制器
    $scope.title = "标题"; // 子作用于反向作用于父控制器
    }],
    // "scope": true // 设置为true 后,父子作用域不通
    };
    }]);
    </script>

    <!-- link.html -->
    <div>
    <h1>{{title}}</h1>
    <input type="text" ng-model="name" />
    </div>
  • true

    创建一个新的作用域,继承自父作用域。

  • {}

    创建与父作用域隔离的新作用域,使在不知道外部环境的情况下可以正常工作,不依赖外部环境。

    可以通过向 scope 的 { } 中传入特殊的前缀标识符(即prefix)来进行数据的绑定。

    在创建了隔离的作用域,我们可以通过 @, &, = 引用应用指令的元素的属性。

    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
    <!-- main.html -->
    <body ng-controller="ctrl">
    <input type="text" ng-model="name" />

    <!-- 一、@单向绑定,这里用的是out-cons,使之可以使用name -->
    <hello out-cons="{{name}}"></hello>

    <!-- 二、=双向项绑定(不需要花括号) -->
    <hello out-cons="{{name}}" out-funs="sum()"></hello>
    </body>
    <script>
    var myApp = angular.module('app', []);
    myApp.controller('ctrl', ["$scope", function ($scope) {
    $scope.name = "张三"; // 这是共享的变量
    $scope.sum = function() { } // 共享的方法
    }]);

    myApp.directive('hello', [function () {
    return {
    "restrict": "E",
    "templateUrl": "view/home.html",
    "scope": {
    "innerCons": "@outCons", // 单向绑定,父作用域改则子作用域改,反之不改
    "innerFuns": "=outFuns", // 双向绑定
    }
    };
    }]);
    </script>

    <!-- link.html -->
    <div>
    <!-- 这里用的是inner(key) -->
    <input type="text" ng-model="innerCons" />
    <span ng-click="innerFuns()">
    </div>

    link 参数要求声明一个链接函数。在此函数中,可操作 template 中的元素,设置样式、添加回调事件等

    1
    2
    function(scope, element, attrs) {
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

- scope: 与指令元素相关联的当前作用域
- element: 当前指令对应的元素,使用它可以操作该元素及其子元素。例如`<span my-directive></span>`,这个 span 就是指令 `my-directive` 所使用的的元素
- attrs: 由当前的元素的属性组成的对象

```js
myApp.directive('hello', [function () {
return {
"restrict": "EA",
"template": "<span>点击</span>",
"link": function(scope, element, attr) {
console.log(element);
element.find("span").addClass("btn btn-success");
element.find("span").on("click", function(){
alert(111);
});
}
};
}]);

require

可以将其他指令穿给自己

  • directiveName 通过驼峰命名法的命名制定了控制器应该带有哪一条指令,默认会从同一个元素上的指令

  • ^directiveName 在父级查找指令

  • ?directiveName 表示指令是可选的,如果找不到,不需要抛出移除

    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-controller="ctrl">
    <!-- dire2 里面要用到 dire1 的函数 -->
    <dire2 dire1></dire2>
    </body>
    <script>
    var myApp = angular.module('app', []);
    myApp.controller('ctrl', ["$scope", function ($scope) {

    }]);

    myApp.directive('dire1', [function () {
    return {
    "restrict": "EA",
    "controller": ['$scope', function($scope) {
    this.getName = function(name) {
    return "name=" + name;
    }
    }]
    };
    }]);
    myApp.directive('dire2', [function () {
    return {
    "restrict": "EA",
    "require": "dire1", // 多个可用数组:["dire1", "dire3"],ctrl参数变为数组类型
    "template": "{{name}}",
    "link": function (scope, element, attrs, ctrl/*ctrl里面的dire2有dire1*/) {
    scope.name = ctrl.getName("张三的name");
    /* require数组时,ctrl也变为数组,使用:ctrl[0].getName("") */
    }
    };
    }]);
    </script>

    父级概念:

    1
    2
    3
    4
    5
    <dire2 dire1></dire2>
    <!-- 下面为父子级,子级可向上require父级 -->
    <dire1>
    <dire2></dire2>
    </dire1>

    $http

    用于读取远程服务器的数据

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    $http({  
    url:url, //请求的url路径
    method:method, //GET/DELETE/HEAD/JSONP/POST/PUT
    params:params , //转为 ?param1=xx1¶m2=xx2的形式
    data: data //包含了将被当做消息体发送给服务器的数据,通常在POST
    }).then(function(response){
    response.data;
    // 请求成功执行代码
    }, function(response){
    // 请求失败执行代码
    });

    $http.get('/someUrl', config).then(successCallback, errorCallback);

    $http.post('/someUrl', config).then(successCallback, errorCallback);

    小提示:ng-repeat 不想要某项重复的话在结尾加:item in list track by $index

    response参数:

  1. data:响应体,就是后台响应后返回的数据。格式为字符串或对象
  2. status:http返回的状态码,如200,表示服务器响应成功
  3. headers(函数):头信息的getter函数,可以接受一个参数,用来获取对应名字的值
  4. config(对象):生成原始请求的完整设置对象
  5. statusText:相应的http状态文本,如”ok”