html 根作用域,AngularJS(七)作用域

当HTML页面中出现ng-app和ng-controller指令时,AngularJS会自动创建作用域对象,我们只需将其注入即可。

1. 根作用域

$rootScope:AngularJS应用启动时会自动创建

2. AngularJS作用域继承

2.1 JavaScript对象继承机制

· JavaScript有两种方式构造对象:一是通过字面量创建var obj = { name: "bob"};

· 二是通过构造方法,JS提供了几个内置的构造方法:Object、 Array、 String等function Person(name) {

this.name = name;

}

var person = new Person("bob");

每个JS构造方法都有一个名称为prototype的属性,可以指向另一个对象。当我们访问对象属性时,JS引擎会从对象的所有属性中查找该属性,如果找到就返回属性值,如果没有找到就继续从prototype属性指向的对象属性中查找,如果仍然没有找到,则会沿着prototype链一直查找下去,直到prototype链结束或找到对象位置。

730ae79cf5a3

除了使用prototype实现继承外,还可以使用apply、call方法实现继承。由于JavaScript构造方法的apply()、call()方法可以改变对象构造中“this”的上下文环境,使特定的对象实例具有对象构造中所定义的属性、方法,因此我们可以使用apply()、call()方法实现JavaScript对象的继承。function Person(name){

this.name = name;

}

function Student(name, love) {

//Person.apply(this,name);

Person.call(this,name);

this.love = love;

}

var student = new Student('bob','pingpong');

上例中,Student对象继承了Person对象的name属性。apply()和call()方法的不同之处在于apply()方法只接受两个参数,第二参数为数组,call()方法可以接收多个参数。

此外,JavaScript中,一个对象可以继承另一个对象的属性。function Person(name) { this.name = name; }

var person = new Person('bob'); var student = Object.create(person); student.love = "pingpong";

Object.getPrototypeOf(student);  // Person

总结一下,JavaScript中有三种对象继承方式:

· prototype     Cat.prototype = new Animal();

· apply()/call()方法    在构造方法中调用这两个方法: Person.call(this, name);

· Object.create(person);

2.2 AngularJS作用域对象原型继承

AngularJS作用域对象继承为JavaScript的第一种方式。AngularJS作用域构造方法中提供了一个$new()成员方法,用于创建子作用域。var parent = $rootScope;

var child = parent.$new();

AngularJS框架遍历DOM元素,查找到ng-app指令时,创建$rootScope作用域。然后AngularJS框架查找到第一个ng-controller指令,指向名称为OuterController的控制器,并调用$rootScope.$new()方法,以原型继承的方式创建$rootScope作用域的子作用域对象($scope1)。当OuterController构造方法接收一个名为$scope的参数时,AngularJS实例化控制器对象时会把$scope1对象注入控制器对象中。

接下来继续遍历,以同样的方式创建$scope1的子作用域,然后将其注入控制器对象中。

3 作用域高级特性

3.1. $watch方法监视作用域

angular.module("wacthModule",[])

.run(["$rootScope", function($rootScope) {

$rootScope.count = 0;

$rootScope.name = "bob";

$rootScope.$watch("name", function() {

$rootScope.count++;

})

}]);

使用作用域对象的$watch()方法对$rootScope中的name属性进行监视。在AngularJS内部,每当我们对ng-model绑定的name属性进行一次修改时,AngularJS内部的$digest循环就会运行一次,并在运行结束之后检查我们使用$watch()方法来监视的内容,如果和上一次进行$digest之前相比有了变化,就执行$watch()方法绑定的处理函数。

在AngularJS作用域对象的$watch()方法中,对基本类型和引用类型的操作有所不同。基本类型的监视与上面的例子一样,引用类型有所不同。

angular.module("wacthModule",[])

.run(["$rootScope", function($rootScope) {

$rootScope.count = 0;

$rootScope.items = [{ "value" : 1},{ "value" : 2}];

$rootScope.$watch("items", function() {

$rootScope.count++;

})

}]);

$watch()方法在对待基本类型和引用类型时会有不同的处理方式,这时需要介绍$watch()方法的第三个参数,第三个参数默认情况下为false。在默认情况下,即不显示指明第三个参数或者将其指明为false时,我们进行的监视叫作引用监视(reference watch),也就是说只要监视对象的引用没有发生变化,就不算它发生变化。在上述例子中,将一个新的数组newItems赋值给items,此时才会认为监视的属性发生了变化,进行回调方法的调用。相反,只要将第三个参数设置为true,此时进行的监视就叫作“全等监视”,只要属性发生变化,就会执行相应的回调方法。

补充:

$watchCollection() :针对数组(集合)进行监视,它的性能介于全等监视和引用监视之间,即它并不会对集合中的每一项的属性进行监视,但是可以对数组的项目增减作出反应。

3.2 解除作用域监视

需要关注$watch()方法的返回值,该方法调用完毕后返回另一个方法,这时只需调用返回的方法即可解除作用域监视。var unbindWatcher = $rootScope.$watch("num", function(newValue, oldValue) {

if (newValue == 2){ unbindWatcher(); }

$rootScope.count++;

});

3.3 $apply方法和$digest循环

实际上AngularJS中的双向绑定也是通过类似于$watch方法的机制实现的。

$digest循环:周期性地运行一个函数来检查scope模型中的数据是否发生了变化。在该循环中,watchers会被触发,当一个watcher被触发时,AngularJS会检测scope模型,如果它发生了变化,那么关联到该watcher的回调方法就会被调用。那么,$digest循环是在什么时候以各种方式开始的呢?

在调用了$scope.$digest()后,$digest循环就开始了。假设你在一个ng-click指令对应的事件处理方法中更改了scope的一条数据,此时AngularJS会自动地通过调用$digest()来触发一轮$digest循环。当$digest循环开始后,它会触发每个watcher,由每一个watcher对属性进行检查,判断是否执行回调函数。

当AngularJS作用域中的模型数据发生变化时,AngularJS会自动触发$digest循环,从而达到自动更新视图的目的。但在有些情况下,模型数据修改后需要我们手动调用$apply()方法来触发$digest循环。例如使用JavaScript的setTimeOut()方法来更新一个模型数据,AngularJS框架就没有办法知道我们修改了什么,也就无法触发$digest循环。这个时候,只要将setTimeOut()方法中的代码移到一个匿名方法中,然后把该匿名方法作为$apply()方法的参数。setTimeOut(function() {

$scope.$apply(function() {

$scope.message = "信息内容";

});

});

3.4 $timeout 与 $interval服务介绍

$timeout 与$interval服务分别是为解决JavaScript中的setTimeOut() 与 setInterval()不能自动触发watcher的问题的方案。使用这两个服务就能够达到JavaScript中的效果,同时还能自动触发$digest循环。$timeout(function(){}, 3000);

4 作用域事件路由与广播

AngularJS作用域支持两种事件传播方式:

· 事件从子作用域路由到父作用域中

· 事件从父作用域广播到所有子作用域

相关的方法有$on()、$emit()、$broadcast()

4.1 $emit方法实现事件路由

该方法用于实现事件从子作用域路由到父作用域中,$emit()方法的第一个参数为事件名称,后面可以传入一个或多个参数,这些参数能够被传递到父作用域注册的事件监听器中,$emit()方法使用如下:$scope.$emit("infoEvent", {name:"bob", age: 12});

消息发送出去后,我们可以在父作用域中调用AngularJS作用域对象的$on()方法,注册一个事件监听器监听子作用域路由的事件:

730ae79cf5a3

730ae79cf5a3

2. $broadcast方法实现事件广播

所有注册了实践监听器的子作用域就能接收到父作用域的广播事件。$scope.$broadcast("infoEvent", {name:"bob"});

3. 作用域对象$on方法详解

$on方法用于注册一个事件监听器,该方法接收两个参数,第一个参数是要监听的事件名称,第二个参数是事件处理方法。$scope.$on("infoEvent", function(event, data) {});

event 参数为事件对象,第二个参数data为调用$emit()或$broadcast()方法传递的数据。需要注意的是,event事件对象具有一些使用的属性和方法。

· event.name: 事件的名称

· event.targetScope: 事件源作用域对象

· event.currentScope: 当前作用域对象

· event.stopPropagation(): 停止事件的进一步传播。该方法只对向父作用域路由事件起作用,当在某个事件监听处理方法中调用事件对象的stopPropagation()方法后,事件不会再向上级父作用域路由。

· event.preventDefault(): 将defaultPrevented属性设置为true,直到事件监听器的实现者采取行动之前才会检查defaultPrevented的值。

· event.defaultPrevented: 如果调用了event.preventDefault()方法,那么该属性将被设置为true。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值