第五章 作用域与事件

一、AngularJS作用域详解
1.$rootScope
AngularJS作用域本质上就是一个普通的JavaScript对象,与普通的JavaScript一样,不同的是不需要手动去构造作用域对象,当HTML页面出现 ng-app ng-controlle r指令时,AngularJS框架会自动创建作用域对象,只需要注入即可
每个AngularJS应用至少有一个 $rootScope ,它是AngularJS应用的根作用域,事实上 $rootScope 是所有作用域的父作用域(孤立作用域除外)
当AngularJS启动时会自动创建一个 $rootScope ,接着当使用 ng-controller 指令实例化控制器对象时,AngularJS框架会为我们创建一个子作用域 $scope ,默认情况下,该 $scope 会继承 $rootScope 的所有属性
-------------------------------------------------controller.js----------------------------------------------------
var app=angular. module ("app",[]);
app. controller ('FirstController',function( $scope , $log ){
$log.info("FirstController->"+$scope.name);
$log.info("FirstController->"+$scope.age);
});
------------------------------------------------------app.html---------------------------------------------------
<!DOCTYPE html>
<html ng-app ="app">
<head>
<meta charset="utf-8">
<title>angularjs</title>
<script type="text/javascript" src="angular.min.js"></script>
<script type="text/javascript" src="controller.js"></script>
</head>
<body ng-init ="name='jane';age='23'">
<div ng-controller ="FirstController"></div>
</body>
</html>
--------------------------------------------------------------------------------------------------------------------
2.可以在ng-controller指令所在范围内使用另一个ng-controller指令实现作用域嵌套,后者会继承前者的作用域

二、AngularJS的作用域继承
1.JavaScript对象继承机制
严格来讲,JavaScript并不是一门面向对象语言,而是一门基于对象的语言
1.1.JavaScript构造对象
(1).通过字面量创建
var obj= {name:'Schuyler',age:'33'};
(2).通过构造方法
function Person(name,age){
this.name=name;
this.age=age;
this.eat=function(){
console.log("eat...");
}
}
----------------
var person= new Person("Schuyler",33);
1.2.构造方法原型链继承
每个JavaScript构造器方法都有一个 prototype 属性,可以指向另一个对象,当
我们访问对象属性时,JavaScript引擎会从对象的所有属性中查找该属性,如果没有
找到就继续从 prototype 属性指向的对象中查找,如果仍没有找到,则会沿着
prototype 链一直查找下去,直到 prototype 链结束或找到对象为止
--------------------------------------------------------------------------------------------------------------------
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>angularjs</title>
</head>
<body>
<script type="text/javascript">
function Animal(){
this.eat=function(){
console.log('eat..');
}
}
function Cat(age){
this.age=age;
}
Cat. prototype = new Animal();
var cat=new Cat(10);
console.log("cat.age="+cat.age);
cat.eat();
</script>
</body>
</html>
--------------------------------------------------------------------------------------------------------------------
1.3.使用apply、call方法实现继承
JavaScript构造方法的 apply() call() 方法可以改变对象构造中的"this"的上下
文环境,使特定对象的实例具有对象构造中所定义的属性、方法,因此我们可以使用
apply() call() 方法实现JavaScript对象的继承
--------------------------------------------------------------------------------------------------------------------
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>angularjs</title>
</head>
<body>
<script type="text/javascript">
function Person(name,age){
this.name=name;
this.age=age;
}
function Student(name,age,love){
//Person. apply(this,[name,age]) ;
Person .call(this,name,age) ;
this.love=love;
}
var student=new Student("Schuyler",23,"code");
console.log("student.name="+student.name);
console.log("student.age="+student.age);
console.log("student.lpve="+student.love);
</script>
</body>
</html>
--------------------------------------------------------------------------------------------------------------------
1.4.对象实例间继承
Object.create() 方法是以一个对象为原型创建另一个对象,创建的对象和原型具
有相同的属性,我们可以通过 Object.getPrototypeOf() 方法获取新对象的原型
--------------------------------------------------------------------------------------------------------------------
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<title>angularjs</title>
</head>
<body>
<script type="text/javascript">
function Person(name,age){
this.name=name;
this.age=age;
}
var person = new Person('jane',28);
var student = Object.create(person) ;
student.love="pingpong";
console.log( Object.getPrototypeOf(student) );
console.log("student.name->:"+student.name);
console.log("student.age->:"+student.age);
console.log("student.love->:"+student.love);
</script>
</body>
</html>
--------------------------------------------------------------------------------------------------------------------
2.AngularJS作用域对象原型继承
AngularJS作用域对象继承采用第一种方式,即构造器方法原型链继承。AngularJS作用域构造方法中提供了一个 $new() 成员方法,用于创建子作用域。过程大致如下:
var parent=$rootScope;
var child=parent. $new() ;

三、作用域高级特性
1. $watch() 方法监视作用域
在使用AngularJS编写应用时,我们经常需要对作用域中的属性进行监视,并对其发生的变化做出相应的处理,AngularJS提供了帮助我们监视作用域属性变化的方法: $watch()
原理:在AngularJS内部,每当我们对 ng-model 绑定的属性进行一次修改时,AngularJS内部的 $digest 循环就会运行一次,并在运行结束之后检查我们使用 $watch() 方法来监视的内容,如果和上一次进行 $digest 之前相比有了变化,就执行我们使用 $watch() 方法绑定的处理函数
$watch() 方法可以接受三个参数,第一个参数是需要监视的属性名称;第二个参数是监视属性发生变化时需要回调的方法,该方法可以传入两个参数,即变化的新值和旧值(可以不传);第三个参数可以不传,默认为false,称为"引用监视","引用监视"下只要监视的对象引用没有发生变化就不算发生变化,当设置为true时,称为"全等监视",此时只要监视的属性发生变化, $watch() 就会执行相应的回调方法
"全等监视"在运行时需要先遍历整个监视对象,然后在每次 $digest 之前使用 angular .copy() 将整个对象深复制一遍,然后再运行之后用 angular . equal() 将前后的对象进行对比,因此在大量数据的复杂环境下可能会消耗大量的资源
另外有 $watchCollection() 方法来针对数组进行监视,它不会对数组中的每一项属性进行监视,但是可以对数组元素的增减做出反应
------------------------------------------------监视基本类型属性--------------------------------------------
<!DOCTYPE html>
<html ng-app="app">
<head>
<meta charset="utf-8">
<title>angularjs</title>
<script type="text/javascript" src="angular.min.js"></script>
</head>
<body>
<input type="text" ng-model ='name'/>
<div>change count: {{count}} </div>
<script type="text/javascript">
angular. module ('app',[])
. run (['$rootScope',function( $rootScope ){
$rootScope .count=0;
$rootScope .name="江荣波";
$rootScope . $watch ('name',function(){
$rootScope .count++;
})
}]);
</script>
</body>
</html>
-------------------------------------------------监视引用类型属性-------------------------------------------
<!DOCTYPE html>
<html ng-app ="app">
<head>
<meta charset="utf-8">
<title>angularjs</title>
<script type="text/javascript" src="angular.min.js"></script>
</head>
<body>
<div ng-repeat ='iteam in items'>
<input ng-model ='item.value'/>
<span> {{item.value}} </span>
<br/><br/>
</div>
<div>change count:{{count}}</div>
<script type="text/javascript">
angular. module ('app',[])
. run (['$rootScope',function( $rootScope ){
$rootScope .count=0;
$rootScope .items=[{"value":1},{"value":2},{"value":3},{"value":4}];
$rootScope . $watch ('name',function(){
$rootScope .count++;
});
}]);
</script>
</body>
</html>
--------------------------------------------------------------------------------------------------------------------
2.作用域监视解除
$watch() 方法的返回值,该方法调用完毕后会返回一个方法,调用该方法即可解除作用域监视
--------------------------------------------------------------------------------------------------------------------
<!DOCTYPE html>
<html ng-app ="app">
<head>
<meta charset="utf-8">
<title>angularjs</title>
<script type="text/javascript" src="angular.min.js"></script>
</head>
<body>
<input ng-model ='num' type='number'/>
<div>change count: {{count}} </div>
<script type="text/javascript">
angular. module ('app',[])
. run (['$rootScope',function( $rootScope ){
$rootScope .count=0;
$rootScope .num=100;
var unbindWatch =
$rootScope. $watch ('num',function( newValue , oldValue ){
if(newValue==2){
unbindWatch ();
}
$rootScope.count++;
});
}]);
</script>
</body>
</html>
--------------------------------------------------------------------------------------------------------------------
3.$apply方法与$digest循环
AngularJS周期性地运行一个函数来检查scope模型中的数据是否发生了变化,这就是所谓的 $digest循环
当写下AngularJS的表达式({{name}})时,AngularJS框架会在幕后为我们在 $scope 中设置一个watcher(与手动 $watch() 方法添加的watcher一样),用来在数据发生变化的时候更新View
假设在 ng-click 指令对应的事件处方法中更改了scope中的一条数据,此时AngularJS会自动的通过调用 $digest() 来触发一轮 $digest循环 ,通常,AngularJS并不直接调用 $digest() 方法,而是调用 $scope . $apply() ,后者会调用 $rootScope . $digest() ,因此一轮 $digest循环 $rootScope 开始,随后会访问所有子作用域中的watcher
$digest循环 中会触发每一个watcher,检测scope模型是否发生了变化,如果发生了变化,那么关联到该watcher的回调方法就会被调用
除了 ng-click 指令,还有一些其他的AngularJS内置指令和服务,比如 ng-model $timeout 服务等,让我们能够更改模型数据和自动触发一次 $digest 循环
4.$apply与$digest应用实战
当作用域中的模型数据发生变化时,AngularJS会自动触发 $digest循环 ,从而达到自动更新视图的目的。但有些情况下时需要自己手动调用 $apply() 方法来触发$digest循环的,例如使用JavaScript的 setTimeout() 方法来更新一个模型数据,此时AngularJS无法知道我们修改了什么,也就无法触发 $digest循环
--------------------------------------------------------------------------------------------------------------------
<!DOCTYPE html>
<html ng-app ="app">
<head>
<meta charset="utf-8">
<title>angularjs</title>
<script type="text/javascript" src="angular.min.js"></script>
</head>
<body>
<div ng-controller ="MsgController">
<div>
<button ng-click =" scheduleTask() ">3秒回显信息
</button>
</div>
<div> {{message}} </div>
</div>
<script type="text/javascript">
angular. module ("app",[])
. controller ("MsgController",
function( $scope ){
$scope .scheduleTask=function(){
setTimeout (function(){
$scope .message='信息内容';
console.log('message='+ $scope .message);
},3000)
}
});
</script>
</body>
</html>
--------------------------------------------------------------------------------------------------------------------
此时需要手动调用 $apply() 方法来触发 $digest循环 $apply() 方法接受一个方法作为参数
--------------------------------------------------------------------------------------------------------------------
<script type="text/javascript">
angular. module ("app",[])
. controller ("MsgController",
function( $scope ){
$scope.scheduleTask=function(){
setTimeout (function(){
    $scope. $apply (function(){
$scope.message='信息内容';
console.log('message='+$scope.message);
});
},3000)
}
});
</script>
--------------------------------------------------------------------------------------------------------------------
5.$timeout与$interval服务介绍
$timeout $interval 是AngularJS提供的功能和JavaScript的 setTimeout() setInterval() 相同的两个 服务 ,使用这两个服务修改作用域属性时会 自动 触发 $digest循环
--------------------------------------------------------------------------------------------------------------------
<!DOCTYPE html>
<html ng-app ="app">
<head>
<meta charset="utf-8">
<title>angularjs</title>
<script type="text/javascript" src="angular.min.js"></script>
</head>
<body>
<div ng-controller ="MsgController">
<div>
<button ng-click =" scheduleTask () ">3秒回显信息
</button>
</div>
<div> {{message}} </div>
</div>
<script type="text/javascript">
angular. module ("app",[])
. controller ("MsgController",
function( $scope , $timeout ){
$scope . scheduleTask =function(){
$timeout (function(){
$scope .message='信息内容';
console.log('message='+$scope.message);
},3000)
}
});
</script>
</body>
</html>
--------------------------------------------------------------------------------------------------------------------

四、作用域事件路由与广播
事件传播机制是AngularJS作用域的另外一个优秀特性,在一些情况下需要在控制器中对一些事件做出处理,例如Ajax请求完成事件,需要通知控制器处理服务端返回的数据,作用域事件传播机制可以帮我们完成这些操作;当我们需要在控制器直接传递数据时,也可以使用作用域事件机制来完成
AngularJS作用域支持两种事件传播方式:
(1).事件从子作用域路由到父作用域中
(2).事件从父作用域广播到所有子作用域中
与AngularJS作用域事件相关的方法有 $on() $emit() $broadcast()
1.$emit()方法实现事件路由(第一种传播方式)
AngularJS作用域对象提供了 $emit() 方法,用于实现事件从子作用域路由到父作用域中,第一个参数为事件名称,后面可以传入一个或多个参数,这些参数能被传递到父作用域注册的事件监听器中
在父作用域中调用AngularJS作用域对象的 $on() 方法,注册一个事件监听器监听子作用域路由的事件,第一个参数为事件名称,第二个参数为事件监听器定义部分,它接收两个参数,第一个参数为事件对象,第二个参数为子作用域中传递的数据
--------------------------------------------------------------------------------------------------------------------
<!DOCTYPE html>
<html ng-app ="app">
<head>
<meta charset="utf-8">
<title>angularjs</title>
<script type="text/javascript" src="angular.min.js"></script>
<style type="text/css">
#parent{
width:350px;
height:250px;
border:3px solid #ccc;
}
#child{
width:300px;
height:200px;
border:3px solid #ccc;
margin:10px auto;
}
</style>
</head>
<body>
<div id="parent" ng-controller ="ParentController">
父作用域
<div id="child" ng-controller ="ChildController">
子作用域<button ng-click =" postEvent ()">Emit</button>
</div>
</div>
<script type="text/javascript">
var app=angular. module ("app",[]);
app. controller ('ParentController',
function( $scope ){
$scope . $on (" infoEvent ",function(event,data){
console.log("接收到子作用域事件...");
console.log(data);
});
});
app. controller ('ChildController',
function( $scope ){
$scope . postEvent =function(){
$scope . $emit (" infoEvent ",{name:"Schuyler",age:23});
}
});
</script>
</body>
</html>
--------------------------------------------------------------------------------------------------------------------
2.$broadcast()方法实现事件广播(第二种传播方式)
$broadcast() 方法的使用与 $emit() 方法相同,不过是由父作用域来广播事件,子作用域只要通过 $on() 方法注册事件监听器即可
--------------------------------------------------------------------------------------------------------------------
<!DOCTYPE html>
<html ng-app ="app">
<head>
<meta charset="utf-8">
<title>angularjs</title>
<script type="text/javascript" src="angular.min.js"></script>
<style type="text/css">
#parent{
width:450px;
height:250px;
border:3px solid #ccc;
}
.child{
width:150px;
height:200px;
border:3px solid #ccc;
float:left;
margin-left:20px;
}
</style>
</head>
<body>
<div id="parent" ng-controller ="ParentController">
<div>父作用域
<button ng-click =" postEvent ()">Broadcast</button>
</div>
<div class="child" ng-controller ="Child1Controller">
子作用域1
</div>
<div class="child" ng-controller ="Child2Controller">
子作用域2
</div>
</div>
<script type="text/javascript">
var app=angular. module ("app",[]);
app. controller ('ParentController',
function( $scope ){
$scope . postEvent =function(){
$scope . $broadcast (" infoEvent ",{name:"Schuyler",age:23});
}
});
app. controller ('Child1Controller',
function( $scope ){
$scope . $on (" infoEvent ",function(event,data){
console.log("子作用域1接收到父作用域事件...");
console.log(data);
});
});
app. controller ('Child2Controller',
function( $scope ){
$scope . $on (" infoEvent ",function(event,data){
console.log("子作用域2接收到父作用域事件...");
console.log(data);
});
});
</script>
</body>
</html>
--------------------------------------------------------------------------------------------------------------------
3.作用域对象$on方法详解
$on() 方法用于注册一个事件监听器,该方法接收两个参数,第一个参数是要监听的事件的名称,第二个参数是事件处理方法
$scope . $on ("infoEvent",function(event,data){……});
事件处理方法接收两个参数,第一个参数 event 为事件对象,第二个参数 data 为调用 $emit() $broadcast() 方法传递的数据
event事件对象具有一些实用的属性和方法:
event. name :事件名称
event. targetScope :事件源作用域对象
event. currentScope :当前作用域对象
event. stopPropagation() :停止事件的进一步传播,只对向父作用域路由事件
起作用,当在某个事件监听处理方法中调用事件对象的 stopPropagation() 方法
后,事件将不会再向上级父作用域路由。对 $broadcast() 无效
event. preventDefault() :将 defaultPrevented 属性设置为true
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值