AngularJS入门
介绍
AngularJS是Google的员工Miško Hevery在2009年着手开发,
2012年发布1.0版本的一个用javascript写的工具.
使用 属性 (比如 ng-show
) 和 表达式 (比如 {{name}}
) 扩展了html,
可以方便地构建单一页面应用程序(SPAs:Single Page Applications).
为此,angularjs几乎包办了页面上的所有成分
- 作为html内容(比如循环输出一个表格)
- 作为javascript内容(比如定义一个两数相加的函数,然后使用)
- 作为css(比如预定义一些css(style),在email验证失败的时候不用style=""定义,自动变红色)
抽象概念
AngularJS的抽象使用了MVC,MVVM相同的理念.
html页面作为view,
在页面中使用形如 ng-model
的指令将页面上数据绑定到viewmodel,
在controller中操作viewmodel中的数据.
然后在页面上使用形如 {{}}` 的表达式将处理结果显示回页面.
### 依赖注入
angular积极使用依赖注入(传递的对象是定义好的函数)的方式来定义对象.
比如
则将model中的数据显示在view中,这种形式称为表达式1
app.controller('myCtrl', function($scope, CaleService) {...});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<html>
<head>
<meta charset="utf-8">
<script src="https://cdn.staticfile.org/angular.js/1.4.6/angular.min.js"></script>
</head>
<body>
<div ng-app="">
<p>名字 : <input type="text" ng-model="name"></p>
<h1>Hello {{name}}</h1>
</div>
</body>
</html>
主要成分(指令另外参考)
指令
形如 ng-show
等,都是指令.
用于实现各种功能
- 页面上的元素与model中的变量绑定
- 显示或隐藏元素
- 重复元素
- 定义下拉框内容
- 定义新的标签等
html5使用 data-
扩展了html,
而AngularJS选择使用 ng-
.
-
TODO ng-app
此处有些混乱,一般是作为app的名字,
但在实现特殊功能时需要使用指定的名字.
在网页加载完毕后自动开始初始化应用程序. -
ng-init
初始化变量,一般不用.
通常使用controller或特殊的module来定义.1
2
3<div ng-app="" ng-init="firstName='John'">
<p>初始化变量的内容是: {{ firstName }}</p>
</div> -
ng-controller
直接定义app所用的controller
1
2
3
4
5<div ng-app="myApp" ng-controller="myCtrl">
...
</div>
<script src="myApp.js"></script>
<script src="myCtrl.js"></script>其中
myApp.js为1
var app = angular.module("myApp", []);
myCtrl.js为
1
2
3
4app.controller("myCtrl", function($scope) {
$scope.firstName = "John";
$scope.lastName= "Doe";
});不过还是要使用app.controller为app添加controller,
不使用ng-controller可能效果也能实现. -
ng-model
声明该标签的值存入绑定至model.
在定义模型后,可以对绑定的变量进行验证.
(尽管例子中使用name来定义和调用,但实测没有ng-model的定义,验证不会生效)
验证会搭配html页面中的元素生效. -
ng-repeat
常和列表或表格或下拉框搭配使用,
指定时可以使用in语法1
2
3
4
5
6
7
8
9
10
11
12<div ng-app="" ng-init="names=[
{name:'Jani',country:'Norway'},
{name:'Hege',country:'Sweden'},
{name:'Kai',country:'Denmark'}]">
list:
<ul>
<li ng-repeat=" x in names">
{{ x.name + ', ' + x.country }}
</li>
</ul>
</div>表格
1
2
3
4
5
6<table>
<tr ng-repeat="x in names | orderBy : 'Country'">
<td>{{ x.Name }}</td>
<td>{{ x.Country | uppercase }}</td>
</tr>
</table>另外
-
ng-options
多用在下拉框中.
1
2
3
4
5
6
7<div ng-app="myApp" ng-controller="myCtrl">
<select ng-model="selectedSite" ng-options="x.site for x in sites"></select>
<h1>你选择的是: {{selectedSite.site}}</h1>
<p>网址为: {{selectedSite.url}}</p>
</div>可以获取整个对象,可以输出x对象下的所有成员.
也可以使用
ng-repeat
实现1
2
3
4
5<select ng-model="selectedSite">
<option ng-repeat="x in sites" value="{{x.url}}">{{x.site}}</option>
</select>
<h1>你选择的是: {{selectedSite}}</h1>但此处显示
x.site
, 值使用x.url
,
在获取到选择的值后不能使用x.site
ng-option
也可以模拟ng-repeat
中只保留一个值的功能1
2
3
4<select ng-model="selectedSite" ng-options="x for (x, y) in sites">
</select>
<h1>你选择的值是: {{selectedSite}}</h1>- 此处显示的是x,而selectedSite无论显示什么,都保存y的部分
-
ng-disabled
若变量为true则控件变为disabled
1
<button ng-disabled="mySwitch">点我!</button>
-
ng-show
若变量为true则显示
1
2<p ng-show="true">我是可见的。</p>
<p ng-show="false">我是不可见的。</p> -
ng-hide
若变量为true则隐藏
1
2<p ng-hide="true">我是不可见的。</p>
<p ng-hide="false">我是可见的。</p> -
ng-if
前面的
ng-show
和ng-hide
在不可见时仍然存在于html中,
可以在检查元素时看到.
ng-if
变量为false时不加入html元素,检查元素也看不到. -
ng-click
定义按钮被按下时调用的函数
1
<button ng-click="toggle()">隐藏/显示</button>
-
ng-include
包含一个其他文件
1
2<div ng-include="'runoob.htm'"></div>
<div ng-include="'https://c.runoob.com/runoobtest/angular_include.php'"></div> -
自定义指令
这样导致指令不一定使用ng开头.
命名上,在定义时使用驼峰式命名,
在调用时使用中间有短线式.(驼峰大写处断开)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15<body ng-app="myApp">
<!-- 此处为调用方法之一 -->
<runoob-directive></runoob-directive>
<script>
var app = angular.module("myApp", []);
app.directive("runoobDirective", function() {
return {
restrict : "A",
};
});
</script>
</body>-
调用方法
-
标签(E)
1
<runoob-directive></runoob-directive>
-
属性(A)
1
<div runoob-directive></div>
-
类名©
1
<div class="runoob-directive"></div>
-
注释(M)
1
<!-- directive: runoob-directive -->
-
-
表达式
形如 {{name}}
,
是表达式,专用于把model中的数据显示在页面上.
表达式中可以写表达式.比如
{{ 5 + 5 }}
计算数字{{ quantity * cost }}
计算变量中的数字{{ "tahta" + " " + cost}}
字符串相加{{person.name}}
取字典中的内容{{array[2]}}
取数组中的内容
{{name}}
与指令 ng-bind="name"
效果相同.
表达式的使用受到作用域的限制.
辅助成分
过滤器
指令和表达式中都能使用.
以管道命令的形式使用.
-
表达式中使用
1
<p>姓名为 {{ lastName | uppercase }}</p>
此外还有
- lowercase
- currency
-
指令中使用
1
2
3
4
5<ul>
<li ng-repeat="x in names | filter:test | orderBy:'country'">
{{ (x.name | uppercase) + ', ' + x.country }}
</li>
</ul>filter
表示匹配字符串orderBy
表示按某个键排序
-
自定义过滤器
定义
1
2
3
4
5
6
7var app = angular.module('myApp', []);
app.filter('reverse', function() { //可以注入依赖
return function(text) {
return text.split("").reverse().join("");
}
});注意使用了 字符串函数名 + 匿名函数
使用
1
2
3<div ng-app="myApp">
姓名: {{ msg | reverse }}
</div>
服务(内建函数)
同 $scope
表示模型本身一样,
其他使用 $
符号定义的也都表示特殊含义
-
$location
获取当前页面的url地址
1
2
3
4var app = angular.module('myApp', []);
app.controller('customersCtrl', function($scope, $location) {
$scope.myUrl = $location.absUrl();
});尽管原生的javascript中也可以通过
window.location
对应,
但比window.location
在对低级浏览器上的兼容性更好一些. -
$http
用于发起http请求,并执行回调函数以响应response.
举例如下1
2
3
4
5app.controller('myCtrl', function($scope, $http) {
$http.get("welcome.htm").then(function (response) {
$scope.myWelcome = response.data;
});
});- 注意在使用之前需要先作为一个参数传入controller
-
标准的用法
1
2
3
4
5
6
7
8
9// 简单的 GET 请求,可以改为 POST
$http({
method: 'GET',
url: '/someUrl'
}).then(function successCallback(response) {
// 请求成功执行代码
}, function errorCallback(response) {
// 请求失败执行代码
}); -
简写的用法
1
2$http.get('/someUrl', config).then(successCallback, errorCallback);
$http.post('/someUrl', data, config).then(successCallback, errorCallback);- 复杂一些的项目可能将
post
和url
的部分放在其他文件(比如前台的路由)中定义,
controller中仅仅用构造data
和successCallback
等
- 复杂一些的项目可能将
-
方法一览
- $http.get
- $http.head
- $http.post
- $http.put
- $http.delete
- $http.jsonp
- $http.patch
-
$timeout
用于延时执行任务,单位ms
1
2
3$timeout(function () {
$scope.myHeader = "How are you today?";
}, 2000);- 同样需要作为参数传入controller
-
$interval
每隔一段时间执行服务,单位ms
1
2
3$interval(function () {
$scope.theTime = new Date().toLocaleTimeString();
}, 1000); -
$index
用在表格等循环结构中,表示序号
1
2
3
4
5
6
7<table>
<tr ng-repeat="x in names">
<td>{{ $index + 1 }}</td>
<td>{{ x.Name }}</td>
<td>{{ x.Country }}</td>
</tr>
</table> -
$even和$odd
多表示循环结构中行数的奇偶
1
2
3
4
5
6
7
8<table>
<tr ng-repeat="x in names">
<td ng-if="$odd" style="background-color:#f1f1f1">{{ x.Name }}</td>
<td ng-if="$even">{{ x.Name }}</td>
<td ng-if="$odd" style="background-color:#f1f1f1">{{ x.Country }}</td>
<td ng-if="$even">{{ x.Country }}</td>
</tr>
</table> -
自定义服务
定义
1
2
3
4
5app.service('hexafy', function() {
this.myFunc = function (x) {
return x.toString(16);
}
});使用
1
2
3app.controller('myCtrl', function($scope, hexafy) {
$scope.hex = hexafy.myFunc(255);
});其他例子
1
2
3
4
5app.filter('myFormat',['hexafy', function(hexafy) {
return function(x) {
return hexafy.myFunc(x);
};
}]);1
2
3<ul>
<li ng-repeat="x in counts">{{x | myFormat}}</li>
</ul>
全局API
有些功能和过滤器重复,不知道高版本的angularjs会不会改善
-
angular.$$lowercase()
**** angular.$$uppercase() -
angular.isString()
-
angular.isNumber()
MVC与controller,scope
ng-model
负责从view到model- controller负责设置model(设置页面上元素的值,控制开关等.)
- 在另外有其他语言的后台程序的项目中,
可以在AngularJS的controller中发起http请求以获取数据等.
- 在另外有其他语言的后台程序的项目中,
{{}}
负责model到view
AngularJS会在js中定义controller的内容,
controller定义在一个名为module的容器中,
可以使用依赖注入的方式为容器定义成员
内部可放入value,constant,controller,filter,service,directive,factory等
添加一个控制器
先获取一个module对象,
然后为module对象添加controller.
分别指定名字和函数行为即可.
1 | <div ng-app="myApp" ng-controller="personCtrl"> |
- 此处controller实现了
ng-init="firstName='John';lastName='Doe'"
的功能. - 可以将model中的变量全看做
$scope
的子成员,此时$scope
即模型本身.- 注意controller代码中才使用
$scope
, html代码中省略不写.
- 注意controller代码中才使用
- 模型中也可以定义函数,定义好的函数常用在表达式中或者
ng-click
等指令后.
分离html文件与js文件
html文件中使用 src
指定引用的js文件路径
1 | <script src="namesController.js"></script> |
应用工具
模型验证及状态
对于form中的元素,angularjs提供了检查状态和验证的功能,
(需要对form内部元素定义name属性和ng-model,实测没有ng-model的定义,验证不会生效)
还提供了配套的css定义等等,
就是为了验证数据后再以各种方式(显示文字,改变底色等等)反馈给使用者
angularjs提供的状态:
$error
表示是否有错误
$valid
表示是否合法
$dirty
值是否改变
$touched
是否被触摸(获取焦点?)
angularjs提供的错误
$error.email
是否违反email格式
$error.required
是否违反required
$error.number
是否违反number格式
等等
AngularJS还可以为input等标签预定义固定名字的设置,
无需 style=""
等方式定义,
进一步将验证的结果可视化
-
举例
- 此处使用了
name
来定义变量的名字,是form中必须使用的. $error.email
需要和type="email"
配合$error.required
需要和required
配合- CSS
ng-invalid
不需要再使用style属性声明
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15<style>
input.ng-invalid {
background-color: lightblue;
}
</style>
<form ng-app="" name="myForm">
<p>邮箱:<br>
<input type="email" name="email" ng-model="email" required>
<span style="color:red" ng-show="myForm.email.$dirty && myForm.email.$invalid">
<span ng-show="myForm.email.$error.required">邮箱是必须的。</span>
<span ng-show="myForm.email.$error.email">非法的邮箱。</span>
</span>
</p>
</form> - 此处使用了
-
相关css属性
ng-empty
ng-not-empty
ng-touched
ng-untouched
ng-valid
ng-invalid
ng-dirty
ng-pending
ng-pristine
单页应用的CSS
-
表格中的使用
1
2
3
4
5
6
7
8
9
10
11
12
13<style>
table, th , td {
border: 1px solid grey;
border-collapse: collapse;
padding: 5px;
}
table tr:nth-child(odd) {
background-color: #f1f1f1;
}
table tr:nth-child(even) {
background-color: #ffffff;
}
</style> -
数据验证中的使用
参见模型验证及状态
动画
引入相应的库
1 | <script src="http://cdn.static.runoob.com/libs/angular.js/1.4.6/angular-animate.min.js"></script> |
使用定义好的模型
1 | <body ng-app="ngAnimate"> |
或
1 | <body ng-app="myApp"> |
然后 ng-hide
等就有了动画效果
-
也可以使用CSS实现动画
例1
1
2
3
4
5
6
7
8
9
10<style>
div {
transition: all linear 0.5s;
background-color: lightblue;
height: 100px;
}
.ng-hide {
height: 0;
}
</style>例2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16<style>
@keyframes myChange {
from {
height: 100px;
} to {
height: 0;
}
}
div {
height: 100px;
background-color: lightblue;
}
div.ng-hide {
animation: 0.5s myChange;
}
</style>
路由
通过路由,AngularJS 可以实现多视图的单页 Web 应用(single page web application,SPA)
-
定义路由
使用
#!
+路径
定义1
2
3
4
5
6
7<h2>AngularJS 路由应用</h2>
<ul>
<li><a href="#!/">首页</a></li>
<li><a href="#!/computers">电脑</a></li>
<li><a href="#!/printers">打印机</a></li>
<li><a href="#!/blabla">其他</a></li>
</ul> -
定义view层资源
使用了module
ngRoute
并在config中注入了$routeProvider
1
2
3
4
5
6
7
8angular.module('routingDemoApp',['ngRoute'])
.config(['$routeProvider', function($routeProvider){
$routeProvider
.when('/',{template:'这是首页页面'})
.when('/computers',{template:'这是电脑分类页面'})
.when('/printers',{template:'这是打印机页面'})
.otherwise({redirectTo:'/'});
}]);