AngularJS
AngularJS是一个开源的网页应用程序的JS框架,由google和一些独立的开发者共同维护,适用于数据操作比较频繁的SPA(Single page application)
AngularJS的4个特点:
1、采用了MVC的设计模式:
2、双向数据绑定:
3、依赖注入:
4、模块化设计:
一、采用了MVC的设计模式:
Model:模型数据
View:视图
Controller:控制器
MVC工作方式:通过操作视图,触发控制器指定的方法,拿到
数据给模型,通过绑定显示在视图中去更新视图。
1、常用表达式与指令
{{}}:直接在页面中显示{{}}中表达式的运算结果
ng-init:用于直接在元素上初始化变量值,如以下代码在页面中的显示为Jack
<span ng-init="name='Jack'">{{name}}</span>
ng-repeat:用于遍历数组或对象
<li ng-repeat="tmp in list">{{tmp}}</li>
<li ng-repeat="(key,value) in car">
{{"key is "+key+" value is "+value}}
</li>
ng-if:用于判断条件,满足则执行相对应的指令
ng-show:值为true则显示相应的View
ng-hide:值为true则隐藏相应的View
ng-click:触发元素click事件
2、MVC简单实现:
1)创建一个模板:
var app=angular.module('模块名称',['依赖列表'])
2)调用模块
<html ng-app="模块名称"></html>
3)创建控制器
app.controller('myCtrl',function($scope){ //*控制器被调用时执行的方法* $scope.count=0; $scope.add=function(){count++;} })
4)调用控制器
<ANY ng-controller='myCtrl'></ANY>
5)模型数据
$scope服务(对象),是一个作用域控制对象,将模型数据定义在$scope中,可供$scope所属Controller的View调用
6)视图
模型数据在View中显示
<div ng-controller="myCtrl"> <p>{{count}}</p> <button ng-click="add()">点我计数</button> </div>
量的方式:
①ngInit
②在控制器中通过$scope定义
建议使用第二种方式,实现结构与行为分离
3、自定义指令
自定义指令方法: app.directive('指令名称',fn)
app.directive('drtName',function(){
return {
template:'<p> Hello Directive </p>', //*指定指令要显示的内容*
restrict:'EACM', //*指令的权限*
replace:true //*替换内容,用在指令作为注释的时候使用*
}
})
restrict:E(Element)、A(Attribute)、C(Class)、M(comment)
4、过滤器
AngularJS中过滤器可用于对Model进行筛选、过滤、格式化,再显示到View中
语法:{{表达式|过滤器1:’参数’|过滤器2:’参数’}}
常用过滤器:
currency:货币样式的格式化
data:日期做处理
ppercase:转换为大写
lowercase:转换为小写
orderBy:对指定Model进行排序,升序|降序
limitTo:限定数组中元素的个数
number:指定小数显示点
<!--将price添加¥前缀-->
<p>{{price | currency:'¥'}}</p>
<!--将日期转化为指定格式-->
<p>{{nowDate | date:"yy-MM-dd"}}</p>
<!--将name转化为指定的格式-->
<p>{{name | uppercase}}</p>
<p>{{name | lowercase}}</p>
<!--将数组根据name进行降序排序-->
<ul>
<li ng-repeat="tmp in list | orderBy:'name':true track by $index">
{{tmp.age +" "+tmp.name }}
</li>
</ul>
<!--限制repeat的数量为2-->
<ul>
<li ng-repeat="tmp in list | limitTo:2">
{{tmp.age +" "+tmp.name }}
</li>
</ul>
</div>
二、双向数据绑定:
1、方向一:Model –> View
点击button,控制器中的funcClick函数使$scope.num不断加一,经过Angular的方向一上的绑定,页面中p标签的num也不断加一
<div ng-controller="myCtrl">
<p>{{num}}</p>
<button ng-click="funcClick()">clickMe</button>
</div>
<script>
var app = angular.module('myModule',['ng']);
app.controller('myCtrl', function ($scope) {
console.log(' in myCtrl ');
$scope.num = 10;
$scope.funcClick = function(){
console.log(' button is pressed ');
}
})
</script>
2、方向二:View(通常表单输入) –>Model
在表单元素上使用ng-model绑定”inputTxt变量”,一旦input中输入的变量发生变化,$scope.inputTxt的值也会发生相应的变化,所以
<p>{{inputTxt}}</p>
中的值也会同步于input表单的输入值发生变化。此时产生了两个方向上的数据绑定:
- View->Model(输入值到inputTxt)
- Model->View(inputTxt到p标签)
<div ng-controller="myCtrl">
<input type="text" ng-model="inputTxt"/>
<p>{{inputTxt}}</p>
</div>
<script>
var app = angular.module('myApp', ['ng']);
app.controller('myCtrl', function ($scope) {
...
});
</script>
3、$watch实现对View的动态监听
在AngularJS中可以使用$scope.$watch(model,callback)对相应的model变化进行监听,倘若model发生变化,则执行相对应的callback
<div ng-controller="myCtrl">
<input type="text" ng-model="inputTxt"/>
<p>{{inputTxt}}</p>
</div>
<script>
var app = angular.module('myApp', ['ng']);
app.controller('myCtrl', function ($scope) {
$scope.$watch('inputTxt',function(){ //使用$scope.$watch监听inputTxt的值
console.log($scope.inputTxt);
})
});
</script>
三、服务
AngularJS中服务指的是一些函数或者对象,可以在整个应用中持有某些行为和状态。控制器虽然有状态,但是并不稳定,可能被多次销毁和重建,所以需要引入服务,而每一个服务都是以一个单例存在
1、控制器间通信:
1)通过$rootScope实现控制器间相互访问
不同的控制器有着不同的作用范围对象,是相互隔离的,是不能直接相互调用的。每一个Angular应用会有一个根作用域$rootScope,在ng启动时初始化id=1,依赖注入的各个控制器的$scope都是$rootScope的子元素。所以可以通过将数据放在$rootScope下进行共享各个控制器间的数据。
<div ng-controller="myCtrl01">
<p>{{"ctrl01 "+num}}</p> <!--显示"ctrl01 10"-->
</div>
<div ng-controller="myCtrl02">
<p>{{"ctrl02 "+num}}</p> <!--显示"ctrl02 100"-->
<p>{{"ctrl02 "+school}}</p> <!--显示"ctrl02 Combridge"-->
</div>
<script>
var app = angular.module('myApp', ['ng']);
app.controller('myCtrl01', function ($scope,$rootScope) {
$scope.num = 10;
console.log($scope); //$scope id 为 2
console.log($rootScope); //$rootScope id 为 1
$rootScope.school='Combridge';
});
app.controller('myCtrl02', function ($scope) {
console.log($scope); //$scope id 为 3
$scope.num = 100;
});
</script>
2)子元素的可以访问到父元素$scope下的属性和方法
<body ng-controller="parentCtrl">
<div ng-controller="myCtrl01">
<button ng-click="funcClick()">clickMe01</button>
</div>
<div ng-controller="myCtrl02">
<button ng-click="funcClick()">clickMe02</button>
</div>
<script>
var app=angular.module('myApp',['ng']);
app.controller('parentCtrl',function($scope){
$scope.funcClick=function () {
console.log("parentCtrl 被点击了");
}
});
app.controller('myCtrl01',function($scope){});
app.controller('myCtrl02',function($scope){});
</script>
3)通过事件发射实现Controller之间的通信:
将事件从父传递给子:
$scope.$broadcast(eventName,data)
将事件从子传递给父:
$scope.$emit(eventName,data);
接受事件以及传递的参数:
$scope.$on(eventName,function(event,data){})
<div ng-controller="myCtrl01">
<button ng-click="callChild()">调用子控制器</button>
<div ng-controller="myCtrl02">
<button ng-click="toChild()">传递数据给子控制器</button>
<div ng-controller="myCtrl03"></div>
</div>
</div>
<script>
var app=angular.module('myApp',['ng']);
app.controller('myCtrl01',function ($scope) {
$scope.$on('event_1',function(event,data){ //接收子元素发送的event_1
console.log(data);
$scope.callChild=data;
})
});
app.controller('myCtrl02',function ($scope) {
$scope.toParent =function () {
console.log('toParent method is called ');
}
/*向父元素发送event_1*/
$scope.$emit('event_1',$scope.toParent);
$scope.toChild=function () {
/*向子元素发送event_2*/
$scope.$broadcast('event_2',"Hello myCtrl03");
}
});
app.controller('myCtrl03',function($scope){
$scope.on('event_2',function(event,data){
console.log(data);
});
})
</script>
2、定时器和计时器
1)原生定时器和计时器
在AngularJS中使用Interval定时器,改变一个Model不会刷新其绑定的View,其原因在于AngularJS的本身循环与原生JS定时器有一个冲突。由双向绑定可知,当我们去做数据绑定时,ng框架会自动地给数据添加一个监听watcher,ng中存在一个$digest方法会周期性地检查模型数据是否发生了变化,每当模型数据发生变化时,就对应有一个回调,更新View。通常ngClick、ngSrc会触发$digest,也可通过手动执行($scope.$digest)。
<div ng-controller="myCtrl"><p>{{num}}</p></div>
<script>
var app=angular.module('myApp',['ng']);
app.controller('myCtrl',function($scope){
$scope.num=0;
setInterval(function(){
$scope.num++;
console.log($scope.num);
/*当不添加$digest时,num会增加,但不会刷新页面*/
/*也可以使用$scope.$apply()代替$scope.$digest()*/
$scope.$digest();
},1000);
})
</script>
2)$interval和$timeout
AngularJS提供了$interval(callback)和$timeout(callback)用于专门的定时和计时操作,在使用前需要注入
app.controller('myCtrl',function($scope,$interval,$timeout){});
$interval(function () { //执行回调
$scope.num++;
},1000)
$timeout(function () { //执行回调
$scope.num++;
},1000)
取消定时器和计时器:$interval.cancel("定时器名")、$timeout.cancel("计时器名")
3、$http服务
1)get请求方式:$http.get $http({methd:'get',url:''})
$http.get('data/test.json').success(function(data){
$scope.studList=data;
})
2)post请求方式:$http.post $http({methd:'post',url:'',data:''})
$http({method:"post",url:"data/test.php"})
.success(function(data){ //成功,data接受数据
console.log(data);
$scope.studList=data;
})
.error(function(error){ //失败,error获取错误
console.log(error);
});
注意:采用post请求服务时,需要初始化设置“Content-Type”:
app.run(function ($http) {
$http.defaults.headers.post = {'Content-Type':'application/x-www-form-urlencoded'};
})
4、自定义服务
1)借助内置的$provide服务
angular.module('myApp',['ng'],function($provide){
//自定义服务
$provide.factory/service/constant/value
})
2)调用模块中的注册方法:factory、service、constant、value
factory:callback直接返回一个对象
app.factory('服务名称',function(){
return {
//返回的属性或方法
}
})
service:function为一个构造函数
app.service('服务名称',function(){
this.name = "";
this.funcCall = function(){}
})
constant和value:对于constant和value所创建的服务,可以通过angular.extend去完成数据的重置
app.constant("服务名称",{})
app.value("服务名称",{})
四、依赖注入
AngualrJS中的服务非常依赖于它的注入系统。任何已有的AngularJS服务都能轻易地通过将它定义为一种依赖来注入到其他服务、指令或者控制器中。依赖注入可以增强代码的重用性、模块化和可测试性,它仅仅是声明而不是创建出所依赖的服务实例,
1、安全地注入:
myModule.controller('MainCtrl',['$log',function($log){}])
,当然前面我们采用了另外一种更简便的注入方式myModule.controller('MainCtrl',function($log){})
。这里我们推荐采用前一种,原因在于,当我们构建完一个应用并进行部署时,通常会进行压缩,所有的JS聚合到一个单一的文件中,注释都被去掉,变量被缩短,导致$log可能变成a这样的简单表示方式,从而失去与原服务的联系。
2、顺序注入:
在
myModule.controller("MainCtrl",["$log","$window",function($w,$l)])
中测试可发现$w代表了$log,$l代表了$window,说明形参的引用与注入的顺序是一一对应的
3、标记式注入:
使用$inject属性来完成标记,该属性是以一个字符型
ctrFunc.$inject = ["$scope","$write"];
注意项:在数组中服务的先后的顺序 要和 控制器的回调中服务的先后顺序要保持一致
4、$injector的使用:
has(“服务名称”): 判断指定的服务是否存在
get(“服务名称”): 得到一个存在的服务的实例对象
两种使用方案:
- 创建一个ng对象的时候,注入$injector
- angular.injector()
var injector=angular.injector(["ng","myApp"]);
if(injector.has("$custom")){
var custom=injector.get("$custom");
custom.print();
}
五、模块化设计
1、模块的调用
在创建模块A的时候,指定模块B写在模块A的依赖列表中
angular.module(‘moduleA’,[‘moduleB’])
一个AngularJS模块一般都由什么构成?
- Service:提供某种对象(变量、方法)
- Controller:控制Model操作
- Directive:绑定Model和View
- Function:完成指定功能
- Filter:过滤、筛选、格式化
<body ng-controller="myCtrl02">
<button ng-click="funcPrint()">clickMe</button>
<script>
var app01=angular.module('myApp01',['ng']);
app01.factory('$custom',function(){
return{
print:function(){
console.log('$custom服务中的方法被调用了')
}
}
})
var app02=angular.module('myApp02',["myApp01"]);
app02.controller('myCtrl02',["$scope","$custom",
function($scope,$custom){
$scope.funcPrint=function(){
$custom.print();
}
}
])
</script>
2、ngRoute模块实现SPA
SPA工作原理:
URL地址:http://127.0.0.1/index.html#/路由地址
- 请求完整的页面地址 index.html
- 解析地址 拿到 ‘#’后面的 路由地址
- 查询路由字典,根据路由地址,找到真实的模板页面的地址
- 发起ajax请求,加载模板页面,插入到DOM
AngularJS中实现SPA的步骤:
创建完整的html页面,引入angular.js angular-route.js
<script src="js/angular-route.js"></script>
创建模块,指定依赖于 ng ngRoute,通过ng-app调用模块
var app = angular.module('myApp',['ng','ngRoute']);
指定一个容器用来盛放代码片段 ngView
<div ng-iew=""></div>
- 创建模板页面
tpl/1.hyml:<div>This is the first page</div>
tpl/2.html:<div>This is the second page</div>
tpl/3.html:<div>This is the third page</div>
配置路由词典
app.config(function($routeProvider){ $routeProvider .when("/first",{controller:'',templateUrl:'tpl/1.html'}) .when("/second",{controller:'',templateUrl:'tpl/2.html'}) .when("/third",{controller:'',templateUrl:'tpl/3.html'}) .otherwise({redirectTo:'/start'}); /*URL中没有路由或出现无效路由则自动重定向到/start页面*/ })
- 发起路由跳转:
直接修改地址栏中的路由地址
超链接<a href='#/myStart'></a>
js来实现跳转$location.path('/myStart');
AngularJS模板页面间实现传参步骤:
明确发送方和接收方
发送:login
接收:main接收方的配置
通过注入$routeParams,然后通过$routeParam.id读取参数
$routeProvider.when('/myMain/:id',{
controller:''
templateUrl:''
}')
- 发送
直接修改地址栏:Url #/myMain/30
超链接:<a href='#/myStart/30'></a>
JS实现跳转:$location.path('/myStart/30')
3、动画模块
Angular中实现动画的步骤
- 引入angular-animate.js
<script src="js/angular-animate.js"></script>
- 创建模板时指定依赖于ngAnimate
var app=angular.module('myApp',['ng','ngAnimate'])
CSS编写
准备离开:
.page.ng-leave{
/*准备离开时状态*/
}
离开完成:
.page.ng-leave.ng-leave-active {
/*离开完成时状态*/
}
开始进入:
.page.ng-enter {
/*开始进入状态*/
}
进入完成:
.page.ng-enter.ng-enter-active {
/*完成进入*/
}