1、Angular.js
Angular.js(简称ng)是Google推出的一款web应用开发框架,它提供了一系列兼容性良好并且可扩展的服务,包括数据绑定、dom操作、mvc设计模式和模块加载等。数据绑定是angular.js最酷最实用的特性,它能够帮助你避免写大量的初始化代码从而节约开发时间,一个典型的web应用可能包含了80%的代码用来处理、查询和监听dom,数据绑定使得代码更少,你就可以专注于你的应用。有了angular.js我们就可以轻松构建SPA(单一页面应用程序)应用程序了。
2、为什么要使用Angular.js?
简单来说就是:写最少的代码,实现更强劲的功能。
如:实现加法运算
- 传统方式实现:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<input id="txt_p1" type = "text">
<span>+</span>
<input id="txt_p2" type = "text">
<input id="btn_add" type = "button" value = "=">
<input id="txt_result" type = "text">
<script>
(function(window , document){
var txt1 = document.querySelector("#txt_p1");
var txt2 = document.querySelector("#txt_p2");
var txtResult = document.querySelector("#txt_result");
var btn = document.querySelector("#btn_add");
btn.addEventListener('click',function (e) {
var t1 = txt1.value - 0 ;
var t2 = txt2.value - 0 ;
txtResult.value = t1 + t2 ;
});
})(window,document)
</script>
</body>
</html>
- angular方式实现:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body ng-app>
<input id="txt_p1" type = "number" ng-model="parameter1">
<span>+</span>
<input id="txt_p2" type = "number" ng-model="parameter2">>
<input id="btn_add" type = "button" value = "=" ng-click=" result = parameter1+parameter2">
<input id="txt_result" type = "number" ng-model="result">
<script src="../bower_components/angular/angular.js"></script>
</body>
</html>
通过上面的代码可以总结:angular.js最大程度的减少了页面上的dom操作,让JavaScript更专注业务逻辑代码。
3.Angular.js的安装
1)下载angular.js的包
下载地址:https://angularjs.org/ 或:https://github.com/angular/angular.js/releases
2)使用bower安装
命令:bower install angular
3)使用npm安装
命令:npm install angular
4)使用cdn的方式
cdn地址:http://cdn.code.baidu.com/
4、Angular.js的第一个示例
<!-- 在ng中以"ng-"开头的成为指令。在ng中所有需要被angular管理的代码都必须被包裹在一个含有"ng-app"指令的元素中
(这个元素不一定非得是body),表示当前元素的所有指令都会被angular管理(即对指令进行分析和操作)。
可以说"ng-app"是angular的入口 -->
<body ng-app>
<h1>使用angular实现双向数据绑定</h1>
<div>
<!--ng-model="user.name"中的"user.name"表示将输入的值绑定到
user对象下的name属性中 -->
<input type="text" placeholder="输入些什么吧。。。" ng-model="user.name" />
</div>
<!-- 在ng中"{{}}"为一个双向数据绑定表达式,它的作用是输出数据模型中的值到元素的innerHTML中 -->
<h4>您输入的内容为:<strong>{{user.name}}</strong></h4>
<script type="text/javascript" src="js/angular.js"></script>
</body>
angular.js的运行原理:
首页需要在有ng代码的父级元素上加上”ng-app”指令,加上这个指令的作用是让ng认识这段代码,告诉ng要去管理这段代码。在ng运行的过程中ng会单独开辟一块存储空间,这块空间的作用是存储当前页面中需要使用的数据模型。当浏览器执行到ng-model="user.name"的时候ng就能认识了,ng-model是作为数据模型绑定的,当ng去解析ng-model="user.name"的时候,存储数据模型的空间中并没有这个模型,因此ng会自动创建一个模型并创建user对象及name属性。这样一来input元素的value属性就与数据模型建立了联系。一旦用户输入了值那么值就会同步到数据模型中.
5、Angular.js的好处
- angular最大程度的减少了页面上的dom操作,让JavaScript更专注于业 务 逻辑。angular解放了传统JavaScript中频繁的dom操作
- 通过简单的指令结合页面结构与逻辑数据
- 通过自定义指令实现组件化编程
- 代码结构更合理,维护成本更低
6、MVC
mvc是一种应用程序的开发思想,并不是一种设计模式。mvc开发思想的主要目的是为了解决应用程序展示结构,业务逻辑之间的紧耦合关系,使应用程序的组成分为三个部件,每个部件都有自己明确的职责,相互之间没有依赖。
6.1、mvc的三大组成部分
- 1)module(模型)
负责处理数据和业务逻辑。(在ng中module在处理数据这块体现的不明显,因为 处理数据一般都是在后台完成的)
- 2)view(视图)
以友好的方式向用户展现数据
- 3)controller(控制器)
组织调度相应的处理模型。它是module与view之间的桥梁。
可以用登录案例理解mvc思想及三大部件的作用(回想Java中的mvc):
- 1)module
a)数据库中所有的用户信息属于module
b)接收控制器传递的用户数据,查询数据库中传递的用户数据是否正确,并响 应用户是否可以登录
- 2)view
a)向用户友好的展示表单
b)接收用户输入的表单数据,并将表单数据传递给controller
- 3)controller
a)接收用户填写的表单数据
b)将表单数据传递给module
6.2、angular中的模块(Module)
angular.js很重要的一个特性就是实现模块化编程,模块在应用程序中就是应用程序的最小单元,我们可以通过小单元的拼合形成一个完整的应用程序。
6.2.1、angular.js中创建module的方式
<!-- ng-app指令是angular用来管理angular代码的,如果自己创建了一个模块,如果想让自己的模块去管理某段代码的内部逻辑的话,
可以将自己创建的模块名称(注意是模块名称,不是变量名称)设置给ng-app指令。当设置好后那么ng-app指令所在元素内的所有代码都
会交由设置的模块管理 -->
<!-- 3、让视图绑定控制器。
当我们写好控制器后我们需要将控制器绑定到视图中。ng-controller="firstModuleController"
表示当前元素交由firstModuleController控制器去控制 -->
<div ng-app="firstModule" ng-controller="firstModuleController">
<h1>Angular中的module</h1>
<input type="text" placeholder="输入些什么吧" ng-model="user.name" />
<div>您输入的内容为:<strong>{{user.name}}</strong></div>
<!-- ng-click="show()"中的show()方法与ng-model="user.name"中的user对象同样是存储在
控制器中的$scope对象中的 -->
<button type="button" ng-click="show()">显示$scope内容</button>
</div>
<script type="text/javascript" src="/angular.js"></script>
<script type="text/javascript">
/*1、注册模块
参数一:模块的名字
参数二:参数二表示当前这个模块所依赖的模块,如果不依赖任何模块也必须传递一个空数组。
如果没有传递第二个参数那么angular.module()方法就不是创建模块,而是获取一个模块
返回值:返回创建的模块对象
*/
var myApp = angular.module("firstModule", []);
/*2、创建控制器
参数一:控制器的名称,一般约定控制器名称为:模块名称+controller
参数二:参数二为一个函数,该函数在控制器执行时会自动执行。该函数也称为控制器函数,
在控制器执行时我们可以在控制器函数中初始化数据模型中的数据及行为
*/
myApp.controller("firstModuleController", function ($scope){
/*$scope参数名称是固定的,这个$scope就是页面中需要用到的数据模型,
也就是说ng-model="user.name"中的user对象就是在这里存储的*/
//在控制器执行时给数据模型赋值
$scope.user = {name: "张三"};
$scope.show = function (){
console.log($scope);
}
});
</script>
6.2.2、一个页面中需要使用多个模块
在我们的开发中一个页面使用多个模块是很正常的,我们想某一段只使用某一个模块就必须在该段的父元素中使用ng-app指令来设置,然后再设置controller。但在ng中一个页面使用多个ng-app指令是不推荐的,那我们应该如何来解决这个问题呢?其实我们可以将多个模块合并成一个模块,然后在父元素中使用ng-app指令来设置这个模块,在指定代码段中设置ng-controller指令即可。
<!--在最外层的父元素中设置module-->
<body ng-app="modules">
<!--在需要使用指定模块的元素中设置模块的controller即可-->
<div ng-controller="btn1ModuleController">
<button type="button" ng-click="showMsg()">按钮1</button>
</div>
<div id="div2" ng-controller="btn2ModuleController">
<button type="button" ng-click="showMsg()">按钮2</button>
</div>
<script type="text/javascript" src="bower_components/angular/angular.js"></script>
<script type="text/javascript">
var module1 = angular.module("btn1Module",[]);
module1.controller("btn1ModuleController", ["$scope", function ($scope){
$scope.showMsg = function (){
console.log("我是按钮1");
}
}]);
var module2 = angular.module("btn2Module",[]);
module2.controller("btn2ModuleController", ["$scope", function ($scope){
$scope.showMsg = function (){
console.log("我是按钮2");
}
}]);
var modules = angular.module("modules", ['btn1Module','btn2Module']);
</script>
</body>
6.3、angular中的控制器(Controller)
6.3.1、控制器的标准语法
<div ng-app="firstModule" ng-controller="firstModuleController">
<h1>Angular中的module</h1>
<input type="text" placeholder="输入些什么吧" ng-model="user.name" />
<div>您输入的内容为:<strong>{{user.name}}</strong></div>
</div>
<script type="text/javascript" src="/angular.js"></script>
<script type="text/javascript">
var myApp = angular.module("firstModule", []);
/*angular在执行控制器函数时,会根据参数的名字($scope)自动往数据模型中注入对象,这个对象不一定是$scope,
假如传递的是$http那么就会自动注入$http对象,它是根据参数名称自动注入对象的。因此这种注入方式有一个问题就是js代码压缩后无法使用,
因为js代码压缩后变量的名称是会改变的,所以这种方式不推荐使用
*/
myApp.controller("firstModuleController", function ($scope){
$scope.user = {name: "张三"};
});
/*======================注入对象的标准方式======================*/
/*使用这种方式注入对象参数二说明:参数二必须是一个数组,数组中的每一个值就是要注入的对象,除数组最后一个值外。
数组最后一个值必须是一个函数(即控制器函数),控制器函数中的参数个数及顺序都是按数组中的值得顺序来的,在该控制器函数中之前怎么写现在还是怎么写*/
myApp.controller("firstModuleController",["$scope",
function (scope){
scope.user = {name: "张三"};
}
])
</script>
6.3.2、控制器的三个职责
- 1)为应用中的数据模型设置初始值
- 2)通过$scope对象把数据模型或函数行为暴露给视图
- 3)监视数据模型的变化,做出相应动作
6.3.4、监视数据模型的变化:$watch()
我们在做注册功能的时候通常都需要用户输入邮箱,然后我们会在用户输入的同时进行格式校验并提示用户输入的邮箱是否合法。以前我们做这种格式校验的时候都是使用了keyup事件,然后在事件里进行判断,使用这种方式有个不好之处就是代码中既有校验的代码又有操作dom的代码。而在angular中要实现这种功能就简单多了,只要我们使用$watch()方法即可。
$watch()只能监视$scope上的成员(不仅仅是属性,方法的返回值也可以)
<div ng-app="watchModule" ng-controller="watchModuleController">
<div>
<label for="email">Email</label>
<input type="text" id="email" ng-model="form.email" >
</div>
<div class="error-tip">{{form.errorTip}}</div>
</div>
<script type="text/javascript" src="angular.js"></script>
<script type="text/javascript">
var watchModule = angular.module("watchModule", []);
watchModule.controller("watchModuleController", ["$scope", function ($scope){
$scope.form = {
errorTip: "请输入Email",
email: ""
}
/*$watch()方法可以监听数据模型中数据的变化。当参数一中表达式的值变化时会执行参数二中的函数
参数一:表示需要监听数据模型中的哪个值
参数二:参数二为一个函数,当参数一中的值变化时会执行该函数
*/
var reg =
/^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+((.[a-zA-Z0-9_-]{2,3}){1,2})$/
$scope.$watch("form.email", function (now,old){
/*now表示当前值,old表示原先的值*/
console.log(now);
if(!reg.test(now)){
$scope.form.errorTip = "您输入的Email不合法!";
}else{
$scope.form.errorTip = "";
}
});
}]);
</script>
6.3.4.1、$watch监视一个对象的值
<body ng-app="angularApply" ng-controller="angularApplyCtrl">
<div><input type="text" ng-model="user.name" /></div>
<div>您更改了:{{updated}}次</div>
<script type="text/javascript" src="angular.js"></script>
<script type="text/javascript">
;(function (angular){
angular.module("angularApply", [])
.controller("angularApplyCtrl", ["$scope",
function ($scope){
$scope.user = { name: "Fox" };
$scope.updated = 0;
/*使用这种方式去监视一个对象是没有用的,因为$watch默认是比较两个对象的引用是否相同,
在这个例子中我们监视$scope.user,当我们改变$scope.user.name时,
对象$scope.user的引用是不会改变的。*/
$scope.$watch('user', function(newValue, oldValue) {
console.log(newValue)
if (newValue === oldValue) { return; }
$scope.updated++;
});
}]);
})(angular);
</script>
</body>
<body ng-app="angularApply" ng-controller="angularApplyCtrl">
<div><input type="text" ng-model="user.name" /></div>
<div>您更改了:{{updated}}次</div>
<script type="text/javascript" src="angular.js"></script>
<script type="text/javascript">
;(function (angular){
angular.module("angularApply", [])
.controller("angularApplyCtrl", ["$scope",
function ($scope){
$scope.user = { name: "Fox" };
$scope.updated = 0;
/*给$watch()传入第三个参数后,表示我们比较的是对象的值,而不是对象的引用,当我们更改$scope.user.name时,
$scope.user的值也就改变了,所以可以正确触发$watch()*/
$scope.$watch('user', function(newValue, oldValue) {
console.log(newValue)
if (newValue === oldValue) { return; }
$scope.updated++;
},true);
}]);
})(angular);
</script>
</body>
6.3.4.2、$watch队列
当我们往视图上绑定一些值时angular就会自动的往$watch队列中添加一个$watch,$watch就是可以用来检测它监视的modle里数据有变化的东西。如代码:
User: <input type="text" ng-model="user" />
Password: <input type="password" ng-model="pass" />
app.controller('MainCtrl', function($scope) {
$scope.foo = "Foo";
$scope.world = "World";
});
在这里我们有两个模型被绑定在了页面上,因此在$watch队列中 会有两个$watch,它们分别监听$scope.foo、$scope.world
<h1>hello,{{world}}</h1>
app.controller('MainCtrl', function($scope) {
$scope.foo = "Foo";
$scope.world = "World";
});
在这里即便$scope中有两个属性,但是只有一个绑定在了视图中,因此在这里$watch队列中只有一个$watch,这个$watch就是用来监视$scope.world的
<ul>
<li ng-repeat=”people in peoples”>
姓名:<span>{{people.name}}</span>,
年龄:<span>{{people.age}}</span>
</li>
</ul>
app.controller('MainCtrl', function($scope) {
$scope.peoples = [...];
});
这里又会生成多少个$watch呢?每个person有两个(name、age各一个),然后ng-repeat又是一个,因此一共是:10*2+1=21,总共有21个$watch。因此每个绑定到了视图上的数据都会生成一个$watch,这些$watch的生成时机是在模板加载完毕时生成的,也就是linking阶段(angular分为compile阶段和linking阶段)
6.4、$scope对象(上下文模型,也称为作用域)
$scope对象的作用主要是用于在视图与控制器之间传递数据,它是视图与控制器之间的桥梁。$scope与数据模型相关联,同时它也是表达式执行的上下文,有了$scope就在视图与控制器之间建立了一个通道,在视图中修改数据时会立刻更新$scope,同样的$scope发生改变时也会立刻渲染视图。
推荐一款chrome浏览器插件”AngularJS Batarang”,它可以查看$scope中暴露出来的所有数据模型